小白_图论1 基础题
1、UVA 10034 最小生成树,水,墨水连点。
2、UVA 10048 floyd,找最小的可行径上的最大边,水,忍受噪音。
3、UVA 10397 最小生成树,题意:架设电缆,但有的点已经相连。 总结:已经相连的点,先连通或者直接标为0。Prim直接过了,但Kruskal一直RE,不知道哪错了。
4、UVA 10369 最小生成树,题意:p个哨点相连,有卫星通道,求最大dis。 总结:题意有点纠结,s个卫星只能有s-1个卫星通道。所以就是第p-s条边。
5、UVA 658 最短路,题意:好迷,查bug,有m个补丁,每个补丁两个字符串s1,s2,s1表示可以用这个补丁的条件,s2表示用后变化。 总结:状态表示成点,但这里好纠结。 不会
6、UVA 10099 floyd,找最大的可行径上的最小边,G[i][j]=max(G[i][j], min(G[i][k],G[k][j])),水,旅游团带人。
7、
8、
9、
思路总结:
/* Floyd 思路总结: 有点像dp,对于G[i][j],介入一个点k(如果存在G[i][k],G[k][j]), 然后在G[i][j]、G[i][k]、G[k][j]之间取最优值。 但Floyd复杂度很高,只能处理范围小的情况 */ int n,m,G[N][N]; void Floyd() { FF(k,1,n) FF(i,1,n) FF(j,1,n) { // k要放在最外层 G[i][j]=max(G[i][j], min(G[i][k],G[k][j])); } }
/* Kruskal 思路总结 然后把所有边按权值排序,遍历。如果这条边相连两点不是一个连通分量, 就利用并查集,把这两点并成一个连通分量。 */ struct Edge { int u,v; double val; friend bool operator < (const Edge &a, const Edge &b) { return b.val>a.val; } }edge[N*N]; int n,m,x[N],y[N]; int tot,father[N]; double Dis(int i,int j) { return sqrt( (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]) ); } void Addedge(int u,int v,double len) { edge[tot].u=u, edge[tot].v=v, edge [tot++].val=len; } int Find(int c) { int p=c,i=c,j; while(father[p]!=p) p=father[p]; while(father[i]!=p) { j=father[i], father[i]=p, i=j; } return p; } bool Unite(int u,int v) { int fau=Find(u), fav=Find(v); if(fau!=fav) { father[fav]=fau; return true; } return false; } double Kruskal() { double sum=0; int num=0; sort(edge,edge+tot); F(i,0,tot) { if(num>=n-1) break; if(Unite(edge[i].u,edge[i].v)) sum+=edge[i].val, num++; } return sum; }
/* Prim 思路总结: n个点分为两个集合U、R,U为已取的点,R为未取的点,先任意取一个点放入U中。 取距离最小的U中点可以到达的R中点,放入U中,如此n-1遍。 */ int vis[N],G[N][N]; double Prim() { double sum=0; vis[1]=1; FF(i,2,n) { //循环n-1次即可 double minn=M; int mi,mj; FF(i,1,n) if(vis[i]==1) { //每次找出未取的距离最小的点 FF(j,1,n) if(vis[j]==0) { if(minn>G[i][j]) { minn=G[i][j], mi=i, mj=j; } } } sum+=G[mi][mj], vis[mj]=1; } return sum; }