ZOJ 3204 Connect them 继续MST
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3367
题目大意:
让你求最小生成树,并且按照字典序输出哪些点连接。无解输出-1
这里的字典序定义为:(不翻译啦~,详见我的比较函数)
A solution A is a line of p integers: a1, a2, ...ap.
Another solution B different from A is a line of q integers: b1, b2, ...bq.
A is lexicographically smaller than B if and only if:
(1) there exists a positive integer r (r <= p, r <= q) such that ai = bi for all 0 < i < r and ar < br
OR
(2) p < q and ai = bi for all 0 < i <= p
思路:
进行kruskal之前排一次序,保证算法选择的边字典序小。
然后输出的时候也要排一次序。
什么时候无解?MST需要N-1条边才能连接所有顶点,所以你就看看边的条数呗。.。。
详见代码。
#include<cstdio> #include<algorithm> using namespace std; const int MAXN=120; const int INF=100000+10; int fa[MAXN]; int n; struct data { int x,y; int dis; }a[MAXN*MAXN],ans[MAXN]; bool operator< (const data& c,const data &d) { if(c.dis<d.dis) return true; else if(c.dis==d.dis) return c.x<d.x || c.x==d.x && c.y < d.y ; return false; } int find(int cur) { return cur==fa[cur]? cur:fa[cur]=find(fa[cur]); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); int len=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { scanf("%d",&a[len].dis); if(a[len].dis==0) continue; a[len].x=i; a[len].y=j; len++; } sort(a,a+len); //保证kruskal的选边是按字典序来的 for(int i=1;i<=n;i++) fa[i]=i; int lena=0; for(int i=0;i<len;i++) { int rootx=find(a[i].x); int rooty=find(a[i].y); if(rootx!=rooty) { fa[rootx]=rooty; ans[lena].x=a[i].x; ans[lena].dis=0; //因为懒得在写比较函数,所以直接设为一样的吧 ans[lena++].y=a[i].y; } } if(n-1!=lena) //MST性质,肯定要n-1条边才能连接所有点 { printf("-1\n"); continue; } sort(ans,ans+lena); //保证输出边也是按字典序来的 for(int i=0;i<lena;i++) { if(i!=0) printf(" "); printf("%d %d",ans[i].x,ans[i].y); } printf("\n"); } return 0; }
新 blog : www.hrwhisper.me