zoj 3202 Second-price Auction
水题,不解释了,直接贴代码
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct node{ int x; int y; }; struct node number[105]; int cmp(struct node a,struct node b){ return a.x>b.x; } int main(){ int t; scanf("%d",&t); int i; while(t--){ int n; scanf("%d",&n); for(i=0;i<n;i++){ scanf("%d",&number[i].x); number[i].y=i; } sort(number,number+n,cmp); printf("%d %d\n",number[0].y+1,number[1].x); } return 0; }
zoj 3203 Light Bulb
简单的数学题,也不解释了,搞成一个双钩函数,最要要注意判断有没有射到墙上即可,直接贴代码
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> using namespace std; int main(){ int t,i; scanf("%d",&t); while(t--){ double H,h,D; scanf("%lf%lf%lf",&H,&h,&D); double tmp=sqrt((H-h)*D); if(tmp+h/H*D<D){ printf("%.3lf\n",h/H*D); } else if(tmp<D){ printf("%.3f\n",H+D-tmp-tmp); } else{ printf("%.3lf\n",h); } } }
zoj 3204 Connect them
最小生成树水题,依旧不解释
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> using namespace std; struct node{ int a,b; int n; }; struct rea{ int a,b; }; struct node edge[10005]; int father[105]; int cmp(struct node a,struct node b){ if(a.n==b.n){ if(a.a==b.a){ return a.b<b.b; } else return a.a<b.a; } return a.n<b.n; } int cmp1(struct rea x,struct rea y){ if(x.a==y.a) return x.b<y.b; else return x.a<y.a; } int Find(int n){ if(father[n]==n) return n; else return father[n]=Find(father[n]); } struct rea relans[500]; int main(){ int t,i,j; scanf("%d",&t); while(t--){ int n; scanf("%d",&n); int k=0; for(i=1;i<=n;i++) father[i]=i; for(i=1;i<=n;i++){ for(j=1;j<=n;j++){ int tmp; scanf("%d",&tmp); if(tmp!=0){ edge[k].a=i; edge[k].b=j; edge[k++].n=tmp; } } } sort(edge,edge+k,cmp); int ans=0; for(i=0;i<k;i++){ int ta=Find(edge[i].a); int tb=Find(edge[i].b); if(ta!=tb){ father[ta]=tb; relans[ans].a=edge[i].a; relans[ans++].b=edge[i].b; } if(ans==n-1) break; } sort(relans,relans+ans,cmp1); if(ans==n-1){ for(i=0;i<ans;i++){ if(i==0) printf("%d %d",relans[i].a,relans[i].b); else printf(" %d %d",relans[i].a,relans[i].b); } printf("\n"); } else{ printf("-1\n"); } } }
zoj 3205 直接贴代码
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<iostream> #include<queue> #include<map> #include<cmath> using namespace std; const int mo= 1000000007; int c[200],p[200][200],a[200]; long long po[105][105]; long long power(int x,int y) { long long res=1; long long sum=x; while (y) { if (y%2==1) res=(res*sum) % mo; sum=(sum*sum) % mo; y/=2; } return res; } int main() { int t; scanf("%d",&t); for (int i=0; i<105; i++) for (int j=0; j<105; j++) po[i][j]=power(i,j); while (t) { int n,m,k; scanf("%d %d ",&n,&m); for (int i=0; i<n; i++) { scanf("%d",&c[i]); for (int j=0; j<m; j++) scanf("%d",&p[i][j]); } scanf("%d",&k); while (k--) { for (int i=0; i<m; i++) scanf("%d",&a[i]); for (int j=0; j<m; j++) { long long ans=0; for (int i=0; i<n; i++) { long long sum=0; if (p[i][j]>0) { sum=c[i]*p[i][j]; for (int k=0; k<m; k++) { if (k==j) sum=(sum*po[a[k]][p[i][k]-1] ) % mo; else sum=(sum*po[a[k]][p[i][k]]) % mo; } } ans=(ans+sum) % mo; } if (j==m-1) cout<<ans<<endl; else cout<<ans<<" "; } } if (--t) cout<<endl; } return 0; }
zoj 3206 Disaster Area Reconstruction
这道题目还是比较麻烦的,题目是叫你求一个连通分量,这个连通分量里面的顶点数是最多的,并输出这个连通分量。
首先,如果这是一个无环图的话,直接树形DP求出最长链就好,所以就要预先处理成环情况。
接着,只要做一遍强连通分量缩点,然后对每个点记录一个顶点数量,再DP一下即可。 代码如下:
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <stack> using namespace std; const int maxn = 50010; const int inf = 1000000; int n, m; vector<int> edge[maxn]; int dfn[maxn], low[maxn], tim; stack<int>s; bool instack[maxn]; int belong[maxn], minId[maxn], num[maxn]; int cnt; void init(){ for(int i = 0; i <= n; i++)edge[i].clear(); while(!s.empty())s.pop(); memset(instack, 0, sizeof(instack)); memset(num, 0, sizeof(num)); memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); fill(minId, minId+maxn, inf); cnt = tim = 0; } void tarjan(int u){ dfn[u] = low[u] = ++tim; s.push(u); instack[u] = 1; int len = edge[u].size(); for(int i = 0; i < len; i++){ int v = edge[u][i]; if(dfn[v] == 0){ tarjan(v); low[u] = min(low[u], low[v]); } else if (instack[v] == 1){ low[u] = min(low[u], dfn[v]); } } if (dfn[u] == low[u]){ int v; cnt ++; do { v = s.top();s.pop(); instack[v] = 0; belong[v] = cnt;//这点缩给哪个新点 num[cnt]++;//缩了多少点 minId[cnt] = min(minId[cnt], v);//缩点的最小点标号 }while(u != v); } } vector<int> newEdge[maxn]; void build(){ for(int i = 0; i <= n; i ++)newEdge[i].clear(); for(int u = 1; u <= n; u++){ int len = edge[u].size(); for(int i = 0; i < len; i++){ int v = edge[u][i]; if(belong[u] != belong[v]){ newEdge[belong[u]].push_back(belong[v]) ; } } } } int vis[maxn]; int dp[maxn]; int tail[maxn]; void init_new(){ for(int i = 0; i <= cnt; i++) newEdge[i].clear(); memset(vis, 0, sizeof(vis)); memset(dp, 0, sizeof(dp)); } void dfs(int u){ vis[u] = 1; dp[u] = num[u]; tail[u] = u; int len = newEdge[u].size(); for(int i = 0; i < len; i++){ int v = newEdge[u][i]; if(vis[v] == 0){ dfs(v); } if(dp[u] < dp[v]+num[u]){ dp[u] = dp[v]+num[u]; tail[u] = tail[v]; } else if( dp[u] == dp[v]+num[u]){ if(minId[tail[u]] > minId[tail[v]]) tail[u] = tail[v]; } } } int main(){ int t; int a, b; scanf("%d", &t); while(t--){ scanf("%d %d", &n, &m); init(); for(int i = 0; i <m; i++){ scanf("%d%d", &a, &b); edge[a].push_back(b); } for(int i = 1; i <= n; i++){ if(dfn[i] == 0){ tarjan(i); } } int ans = 0; init_new(); build(); for(int i = 1; i <= cnt; i ++){ if(vis[i] == 0){ dfs(i); } } pair<int, int> res = make_pair(inf, inf); for(int i = 1; i <= cnt; i ++){ a = minId[tail[i]], b = minId[i]; pair<int, int> tmp = make_pair(a, b); if(dp[i] > ans){ ans = dp[i]; res = tmp; } else if( dp[i] == ans ) { if ( tmp < res && res.first != res.second || tmp.first == tmp.second ){ res = tmp; } } } if(res.first == res.second) { res = make_pair(1, 2); } printf("%d\n%d %d\n", ans, res.first, res.second); } }
zoj 3207 80ers‘ Memory
水题,不解释了,代码也不上了
zoj 3208 Reforestation
这道题目讲多一点,题目意思是:有一个观测者正在观测周围情况,观测者一直在(0,0)的位置。 题目给你一些树的圆心,这些树每秒钟半径为多1,如果这些树相互碰撞或者碰到了观测者,那它们就会停止生长,它们会挡住观测者的视线,题目问的是观测者什么时候被挡住?如果挡不住的话就输出-1.
思路:
首先可以先预处理出来每颗树什么时候停止生长,就是每棵树和其他所有的树算一个相交时间取最小即可。然后就可以想到二分时间,取所有停止时间中最大的作为最大时间进行二分,对于每一个时间只要计算观测者是否被挡住即可。 具体的计算的话,只需要看是否[0,2π]范围内的视野全被挡住了,如果挡住了,你懂得。
代码如下
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> #include<iostream> #include<queue> #include<map> #include<cmath> using namespace std; const double o=1e-8; const double pi = acos(-1.0); struct da { double x,y,t; } a[10000]; struct da1 { double l,r; }q[10000]; int n,bo[400]; double ti[100000]; double min(double x, double y) { return x<y?x:y; } double max(double x,double y) { return x>y?x:y; } double dis(int i,int j) { return sqrt( (a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y) ); } bool cmp(da1 a, da1 b) { return a.l<b.l; } bool cmp2(double a,double b) { return a<b; } bool check(double res) { int sum=0; for (int i=1; i<=n; i++) { double r = min(res,a[i].t); double ph1,ph2; ph1 = atan2(a[i].y,a[i].x); if (ph1<0) ph1+=pi*2; if ( r-dis(0,i)<o ) ph2 = asin(r/dis(0,i)); else ph2=pi/2.0; double lnow=ph1-ph2,rnow=ph1+ph2; if (lnow<0) { q[sum].l=lnow+pi*2; q[sum].r=pi*2; sum++; q[sum].l=0; q[sum].r=rnow; sum++; } else if (rnow>pi*2) { q[sum].l=lnow; q[sum].r=pi*2; sum++; q[sum].l=0; q[sum].r=rnow-pi*2; sum++; } else { q[sum].l=lnow; q[sum].r=rnow; sum++; } } sort(q,q+sum,cmp); double rnow=o; for (int i=0; i<sum; i++) { if (q[i].l>rnow) return true; rnow = max(rnow,q[i].r); } if (rnow<pi*2) return true; return false; } int main() { int t; scanf("%d",&t); while (t--) { scanf("%d",&n); a[0].x=0,a[0].y=0; a[0].t=0; for (int i=1; i<=n; i++) { int x,y; scanf("%d %d",&x,&y); a[i].x=x,a[i].y=y; a[i].t=999999; } double l=0.0,r=0.0; memset(bo,0,sizeof bo); bo[0]=true; for (int i=1; i<=n; i++) { int tt=0; double mint=999999; for (int j=1; j<=n; j++) if (!bo[j]) { double tmp=dis(0,j); for (int k=1; k<=n; k++) if (j!=k){ if (!bo[k]) tmp=min(tmp,dis(j,k)/2.0); else tmp=min(tmp,dis(j,k)-a[k].t); } if (tmp<mint) { tt=j; mint=tmp; } } bo[tt]=true; a[tt].t=mint; } for (int i=1; i<=n; i++) r=max(r,a[i].t); r+=1.0; if ( check(r) ) cout<<"-1.0"<<endl; else { while (r-l>1e-8) { double mid=(l+r)/2.0; if (check(mid)) l=mid; else r=mid; } printf("%.8f\n",l); } } return 0; }
zoj 3209 Treasure Map
用n*m作为列,每个矩阵作为行,Dancing Link不解释了
#include<stdio.h> #include<string.h> const int ROW = 505; const int V = 452000; const int LIE = 905; int R[V],L[V],U[V],D[V],C[V]; int H[ROW],S[LIE]; int n,m; int size; int ans; void link(int r,int c) { S[c]++;C[size]=c; U[size]=U[c];D[U[c]]=size; D[size]=c;U[c]=size; if(H[r]==-1) H[r]=L[size]=R[size]=size; else { L[size]=L[H[r]];R[L[H[r]]]=size; R[size]=H[r];L[H[r]]=size; } size++; } void remove(int c) { int i,j; L[R[c]]=L[c]; R[L[c]]=R[c]; for(i=D[c];i!=c;i=D[i]) { for(j=R[i];j!=i;j=R[j]) { S[C[j]]--; U[D[j]]=U[j]; D[U[j]]=D[j]; } } } void resume(int c) { int i,j; for(i=U[c];i!=c;i=U[i]) { for(j=L[i];j!=i;j=L[j]) { S[C[j]]++; U[D[j]]=D[U[j]]=j; } } L[R[c]]=c; R[L[c]]=c; } void Dance(int k){ int Min,i,j,c; if(R[0]==0){ if(ans>k){ ans=k; } return ; } for(Min=ROW,i=R[0];i;i=R[i]){ if(Min>S[i]) { Min=S[i]; c=i; } } remove(c); for(i=D[c];i!=c;i=D[i]){ for(j=R[i];j!=i;j=R[j]){ remove(C[j]); } Dance(k+1); for(j=L[i];j!=i;j=L[j]){ resume(C[j]); } } resume(c); } int main(){ int t,i,j,row; scanf("%d",&t); while(t--){ int p; scanf("%d%d%d",&n,&m,&p); int count=n*m; for(i=0;i<=n*m;i++){ S[i]=0; U[i]=D[i]=i; L[i+1]=i;R[i]=i+1; } R[n*m]=0; size=n*m+1; for(row=1;row<=p;row++){ H[row]=-1; int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); for(i=x1;i<x2;i++){ for(j=y1;j<y2;j++){ link(row,i*m+j+1); } } } ans=ROW; Dance(0); if(ans==ROW){ printf("-1\n"); } else{ printf("%d\n",ans); } } }
zoj 3210 3211 3212 都是水题不解释了
时间: 2024-10-01 04:50:14