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 }

 

posted @ 2013-02-19 14:22  silver__bullet  阅读(465)  评论(0编辑  收藏  举报