题意
已知有一张 n 个点的图, 以及两两的最小割, 构造出一张合法的原图.
n <= 1000 .
分析
假设存在合法原图, 最小割树即是最小生成树.
求出最小生成树, 判定任意点对间是否满足, 然后再输出最小割树即可.
实现
1 #include <cstdio> 2 #include <iostream> 3 #include <cctype> 4 #include <algorithm> 5 using namespace std; 6 7 #define F(i,a,b) for (int i=(a);i<=(b);i++) 8 9 const int N=105; 10 const int L=10005; 11 const int E=205; 12 const int INF=~0u>>1; 13 14 int n; 15 int p[N][N]; 16 17 int m; 18 struct Ed { 19 int u,v,d; 20 inline Ed(int _u=0,int _v=0,int _d=0):u(_u),v(_v),d(_d){} 21 friend inline int operator < (Ed a,Ed b) { 22 return a.d>b.d; 23 } 24 }ed[L]; 25 26 int f[N]; 27 struct Graph { 28 int v,d,nx; 29 inline Graph(int _v=0,int _d=0,int _nx=0):v(_v),d(_d),nx(_nx){} 30 }mp[E]; 31 int tot,hd[N]; 32 33 int dis[N][N]; 34 35 inline int rd(void) { 36 int x=0,f=1; char c=getchar(); 37 for (;!isdigit(c);c=getchar()) if (c==‘-‘) f=-1; 38 for (;isdigit(c);c=getchar()) x=x*10+c-‘0‘; 39 return x*f; 40 } 41 42 int Find(int x) { 43 if (f[x]==x) return x; 44 else return f[x]=Find(f[x]); 45 } 46 inline void Ins(int u,int v,int d) { 47 mp[++tot]=Graph(v,d,hd[u]); hd[u]=tot; 48 mp[++tot]=Graph(u,d,hd[v]); hd[v]=tot; 49 } 50 51 void DFS(int *a,int x,int pre) { 52 for (int k=hd[x];k>0;k=mp[k].nx) 53 if (mp[k].v!=pre) { 54 a[mp[k].v]=min(a[x],mp[k].d); 55 DFS(a,mp[k].v,x); 56 } 57 } 58 59 int main(void) { 60 #ifndef ONLINE_JUDGE 61 freopen("sdchr.in","r",stdin); 62 freopen("sdchr.out","w",stdout); 63 #endif 64 65 cin>>n; F(i,1,n) F(j,1,n) p[i][j]=rd(); F(i,1,n) p[i][i]=INF; 66 67 F(i,1,n) F(j,1,n) 68 ed[++m]=Ed(i,j,p[i][j]); 69 sort(ed+1,ed+m+1); 70 F(i,1,n) f[i]=i; tot=1; 71 F(i,1,m) { 72 int u=ed[i].u,v=ed[i].v,d=ed[i].d; 73 int fu=Find(u),fv=Find(v); 74 if (fu!=fv) { 75 Ins(u,v,d); 76 f[fu]=fv; 77 } 78 } 79 80 F(i,1,n) { 81 dis[i][i]=INF; 82 DFS(dis[i],i,-1); 83 } 84 F(i,1,n) F(j,1,n) if (dis[i][j]!=p[i][j]) { 85 printf("-1\n"); return 0; 86 } 87 cout<<n-1<<endl; 88 for (int i=2;i<=tot;i+=2) { 89 int x=mp[i].v,y=mp[i^1].v,d=mp[i].d; 90 printf("%d %d %d\n",x,y,d); 91 } 92 93 return 0; 94 }
时间: 2024-10-18 03:50:47