又来吐吐糟啦。。。
今天还算顺利,总共刷出了5题。
前两题是并查集,就是昨天没搞定的。后面三题都是最短路径了。
简单说说这几题吧。
关于并查集的两题其实都是卡在了路径压缩的处理上。很坑爹的说。其实也就是在路径压缩时
利用数组记录下一些信息。在需要的时候在合理的计算出来。
其实,挺难理解的。。。
我也只是一知半解了。。。
第一题(HDU1829)
主要是判断两个人是否在同一连通分量的同一层次上。那个计算层次的两个公式,较难理解。
代码:
#include<iostream> #include<cstring> using namespace std; const int maxn=2001; int father[maxn],layer[maxn],numBug,actionBug; bool flag; void init() { memset(layer,0,sizeof(layer)); for(int i=1;i<=numBug;i++) { father[i]=i; } } int find(int x) { if(x!=father[x]) { int tmp=father[x]; father[x]=find(father[x]); layer[x]=(layer[x]+layer[tmp])%2; } return father[x]; } void combine(int x,int y) { int fx=find(x); int fy=find(y); if(fx==fy) { if(layer[x]==layer[y]) flag=true; } else { father[fx]=fy; layer[fx]=(layer[x]+layer[y]+1)%2; } } void deal() { flag=false; int x,y; for(int i=1;i<=actionBug;i++) { scanf("%d%d",&x,&y); if(!flag) combine(x,y); } } int main() { int cas,t=1; scanf("%d",&cas); while(cas--) { scanf("%d%d",&numBug,&actionBug); init(); deal(); printf("Scenario #%d:\n",t++); if(flag) printf("Suspicious bugs found!\n\n"); else printf("No suspicious bugs found!\n\n"); } system("pause"); return 0; }
第二题(HDU3635)
这题的难点在于求ball的转移次数。
暴力解法是每次Q A时都暴力找到和A同祖先的ball,然后把转移次数加一,O(n^2)的算法,TLE了。
另外的解法就是在路径压缩时利用路径压缩的特点来解,难点也就是这个了。
如果你是我的祖先,你的转移次数加上我的转移次数才是我的转移次数,否则你早已不是我的祖先
了。只有直接转移祖先路径才不会被压缩,否则压缩。
代码:
#include<iostream> #include<cstring> using namespace std; const int maxn=10001; int father[maxn]; int transport[maxn]; int numBall[maxn]; int N,K,t=1; int find(int x) { if(x!=father[x]) { int temp=father[x]; father[x]=find(father[x]); transport[x]+=transport[temp]; } return father[x]; //if(x==father[x]) //{ // return x; //} //return father[x]=find(father[x]); } void combine(int x,int y) { int fx=find(x); int fy=find(y); if(fx==fy) return; father[fx]=fy; transport[fx]++; numBall[fy]+=numBall[fx]; } void init() { memset(transport,0,sizeof(transport)); for(int i=1;i<=N;i++) { father[i]=i; numBall[i]=1; } } void inputAndQuary() { int i,a,b; char ch; printf("Case %d:\n",t++); for(i=0;i<K;i++) { getchar(); scanf("%c",&ch); if(ch=='T') { scanf("%d%d",&a,&b); combine(a,b); } else { scanf("%d",&a); int tmp=find(a); printf("%d %d %d\n",tmp,numBall[tmp],transport[a]); } } } int main() { int cas; scanf("%d",&cas); while(cas--) { scanf("%d%d",&N,&K); init(); inputAndQuary(); } system("pause"); return 0; }
后面三题全是最短路径问题。(HDU2066、2544、1874)
还都是用SPFA算法来解的。代码都非常相似,我就放在一次讲啦。
不过,问题时我用模板过了2066、2544,却卡在了1874,数次WA呀。。。
这就让我纠结了。
神马情况呀。前面都过了。
找这种错误是最难的,最纠结的。因为我认为木有问题呀。从逻辑到数据都是经过检验的呀。
花了很长时间,一直忍着没找度娘。功夫不负有心人呀。最后发现模板中有一个函数的代码
有问题,就这样也过了2066、2544。。。这数据没的说了。。。
代码:
#include<iostream> #include<vector> #include<queue> #include<cstring> using namespace std; const int maxn=1001; const int INF=0x7fffffff; struct node { int to; int cost; }; vector<node> myV[maxn]; //利用临界表存储图 int numRoad,numFrom,numTo; //路径数、可以开始的地点数、想去的地点数 int minPath[maxn],canFrom[maxn],wantTo[maxn]; //最短路、可以出发的城市、想去的城市 bool inQ[maxn]; //是否入队 /* 有bug的函数 bool judgeExistAndSmall(int a,int b,int time) { bool flag=false; for(int i=0;i<myV[a].size();i++) { if(myV[a][i].to==b) { if(myV[a][i].cost>time) { myV[a][i].cost=time; flag=true; break; } } } if(flag) { for(int j=0;j<myV[b].size();j++) { if(myV[b][j].to==a) { myV[b][j].cost=time; break; } } } if(flag) return true; return false; } */ bool judgeExistAndSmall(int a,int b,int time) { bool flagExist=false,flagSmall=false; //路径是否存在、存在的路径是否更小 for(int i=0;i<myV[a].size();i++) { if(myV[a][i].to==b) { flagExist=true; if(myV[a][i].cost>time) { myV[a][i].cost=time; flagSmall=true; break; } } } if(flagSmall) //双向图,只有存在的路径更小才需要处理 { for(int j=0;j<myV[b].size();j++) { if(myV[b][j].to==a) { myV[b][j].cost=time; break; } } } if(flagExist) return true; //只要存在路径就返回true return false; } void inputItial() { int i,a,b,time; for(i=0;i<maxn;i++) //清空再使用 { myV[i].clear(); } for(i=0;i<numRoad;i++) { scanf("%d%d%d",&a,&b,&time); if(!judgeExistAndSmall(a,b,time)) //无向图、判断是否存在了路、存在的路是大是小 { node tmp; tmp.cost=time; tmp.to=b; myV[a].push_back(tmp); tmp.to=a; myV[b].push_back(tmp); } } for(i=0;i<numFrom;i++) { scanf("%d",&canFrom[i]); } for(i=0;i<numTo;i++) { scanf("%d",&wantTo[i]); } } void SPFA() //最短路径快速算法 Shortest Path Faster Algorithm { int minCost=INF; for(int i=0;i<numFrom;i++) { memset(inQ,false,sizeof(inQ)); for(int j=0;j<maxn;j++) { minPath[j]=INF; } minPath[canFrom[i]]=0; queue<int> myQ; myQ.push(canFrom[i]); inQ[canFrom[i]]=true; int now,to,cost; while(!myQ.empty()) { now=myQ.front(); myQ.pop(); for(int k=0;k<myV[now].size();k++) { to=myV[now][k].to; cost=myV[now][k].cost+minPath[now]; if(minPath[to]>cost) { minPath[to]=cost; if(!inQ[to]) { inQ[to]=true; myQ.push(to); } } } inQ[now]=false; } for(int kk=0;kk<numTo;kk++) { minCost=min(minCost,minPath[wantTo[kk]]); } } printf("%d\n",minCost); } int main() { while(scanf("%d%d%d",&numRoad,&numFrom,&numTo)==3) { inputItial(); SPFA(); } system("pause"); return 0; }
最后,到这么晚才写实在不好意思。
看电视的说。。。