又来吐吐糟啦。。。
今天还算顺利,总共刷出了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;
}
最后,到这么晚才写实在不好意思。
看电视的说
。。。
本文详细解析了并查集算法中路径压缩的处理技巧,通过具体实例介绍了如何利用并查集解决复杂问题,并探讨了最短路径算法中的SPFA算法实现及其调试过程。
3455

被折叠的 条评论
为什么被折叠?



