4519: [Cqoi2016]不一樣的最小割ios
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 489 Solved: 301
[Submit][Status][Discuss]
Descriptionc++
學過圖論的同窗都知道最小割的概念:對於一個圖,某個對圖中結點的劃分將圖中全部結點分紅
兩個部分,若是結點s,t不在同一個部分中,則稱這個劃分是關於s,t的割。對於帶權圖來講,將
全部頂點處在不一樣部分的邊的權值相加所獲得的值定義爲這個割的容量,而s,t的最小割指的是在
關於s,t的割中容量最小的割。
而對衝刺NOI競賽的選手而言,求帶權圖中兩點的最小割已經不是什麼難事了。咱們能夠把
視野放寬,考慮有N個點的無向連通圖中全部點對的最小割的容量,共能獲得N(N−1)
2個數值。
這些數值中互不相同的有多少個呢?這彷佛是個有趣的問題。
Input算法
輸入文件第一行包含兩個數N,M,表示點數和邊數。接下來M行,每行三個數u,v,w,
表示點u和點v(從1開始標號)之間有條邊權值是w。
1<=N<=850 1<=M<=8500 1<=W<=100000
Outputspa
輸出文件第一行爲一個整數,表示個數。code
Sample Inputip
4 4get
1 2 3string
1 3 6it
2 4 5io
3 4 4
Sample Output
3
補了一下等價流樹Gusfield算法
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorithm> #include<queue> #include<set> using namespace std; #define LL long long int read() { int s=0,f=1;char ch=getchar(); while(!('0'<=ch&&ch<='9')){if(ch=='-')f=-1;ch=getchar();} while('0'<=ch&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();} return s*f; } int n,m; int be[855],bn[17005],bv[17005],bl[17005],bw=1; int ce[855],cn[17005],cv[17005],cl[17005],cw=1; void put(int u,int v,int l) {cw++;cn[cw]=ce[u];ce[u]=cw;cv[cw]=v;cl[cw]=l;} int dis[855]; bool bfs(int s,int t) { for(int i=1;i<=n;i++)dis[i]=1000000,be[i]=ce[i]; dis[s]=1; queue<int>q; for(q.push(s);!q.empty();) {int x=q.front();q.pop(); for(int i=be[x];i;i=bn[i]) if(bl[i]&&dis[bv[i]]>dis[x]+1) {dis[bv[i]]=dis[x]+1; q.push(bv[i]); } } return dis[t]<=n; } int dinic(int x,int T,int f) { if(x==T) return f; int sum=0; for(int &i=be[x];i&&f;i=bn[i]) if(bl[i]&&dis[bv[i]]==dis[x]+1) {int s=dinic(bv[i],T,min(f,bl[i])); f-=s;sum+=s; bl[i]-=s,bl[i^1]+=s; } return sum; } int cut(int u,int v) { int sum=0; for(int i=1;i<=cw;i++)bn[i]=cn[i],bl[i]=cl[i],bv[i]=cv[i]; while(bfs(u,v)) sum+=dinic(u,v,850000000); return sum; } int f[855]; set<int>s; int main() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); n=read(),m=read(); for(int i=1;i<=m;i++) {int u=read(),v=read(),w=read(); put(u,v,w); put(v,u,w); } for(int i=2;i<=n;i++)f[i]=1; for(int u=2;u<=n;u++) {int v=f[u]; s.insert(cut(u,v)); for(int j=u+1;j<=n;j++) if(f[j]==v&&dis[j]<=n) f[j]=u; } printf("%d\n",s.size()); //fclose(stdin); //fclose(stdout); return 0; }