hdu 1853 Cyclic Tour
题意:
给定一个有向图,把图分成一些环,要求每个点只属于一个环,求满足条件的环所有边权和的最小值。
解法:
对于满足条件的环,每个点的入度和出度均为1,我们可以把每个点拆成入点和出点,那么也就是说一个入点对应一个出点,反之亦然,那么这个问题就变成了一个二分图匹配问题,因为要取最小值,我们可以把每条边的权值取相反数,然后求一次最优匹配,对求得的结果再取相反数即为答案。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 110 5 using namespace std; 6 const int inf=1<<30; 7 int s[N][N]; 8 int lx[N],ly[N],mat[N],slack[N],n; 9 bool vx[N],vy[N]; 10 void checkmin(int &a,int b){ 11 if(a>b)a=b; 12 } 13 void checkmax(int &a,int b){ 14 if(a<b)a=b; 15 } 16 bool dfs(int u){ 17 vx[u]=1; 18 for(int i=1;i<=n;i++){ 19 if(!vy[i]){ 20 int t=lx[u]+ly[i]-s[u][i]; 21 if(t==0){ 22 vy[i]=1; 23 if(mat[i]==-1||dfs(mat[i])){ 24 mat[i]=u; 25 return 1; 26 } 27 }else checkmin(slack[i],t); 28 } 29 } 30 return 0; 31 } 32 int KM(){ 33 for(int i=1;i<=n;i++){ 34 lx[i]=-inf; 35 for(int j=1;j<=n;j++) 36 checkmax(lx[i],s[i][j]); 37 } 38 memset(mat,-1,sizeof(mat)); 39 memset(ly,0,sizeof(ly)); 40 for(int i=1;i<=n;i++){ 41 for(int j=1;j<=n;j++) 42 slack[j]=inf; 43 while(1){ 44 memset(vx,0,sizeof(vx)); 45 memset(vy,0,sizeof(vy)); 46 if(dfs(i))break; 47 int d=inf; 48 for(int j=1;j<=n;j++) 49 if(!vy[j])checkmin(d,slack[j]); 50 for(int j=1;j<=n;j++) 51 if(vx[j])lx[j]-=d; 52 for(int j=1;j<=n;j++) 53 if(vy[j])ly[j]+=d; 54 } 55 } 56 int ans=0,cnt=0; 57 for(int i=1;i<=n;i++) 58 if(mat[i]!=-1&&s[mat[i]][i]!=-inf){ 59 ans+=s[mat[i]][i]; 60 ++cnt; 61 } 62 if(cnt!=n)return -1; 63 return -ans; 64 } 65 int main(){ 66 int m; 67 while(~scanf("%d%d",&n,&m)){ 68 for(int i=1;i<=n;i++) 69 for(int j=1;j<=n;j++) 70 s[i][j]=-inf; 71 for(int i=1;i<=m;i++){ 72 int u,v,w; 73 scanf("%d%d%d",&u,&v,&w); 74 if(-w>s[u][v])s[u][v]=-w; 75 } 76 int ans=KM(); 77 printf("%d\n",ans); 78 } 79 return 0; 80 }