【uva 1349】Optimal Bus Route Design(图论--网络流 二分图的最小权完美匹配)

题意:有一个N个点的有向带权图,要求找若干个有向圈,使得每个点恰好属于一个圈。请输出满足以上条件的最小权和。

解法:有向圈?也就是每个点有唯一的后继。这是一个可逆命题,同样地,只要每个点都有唯一的后继,那么它们一定恰好属于一个圈。而“唯一”可以想到二分图匹配。把每个点拆成两个点,分别放在二分图的两边。两侧的点连的边就是原来的边的转化,另外再给源点和汇点分别连 n 条容量为1、费用为0的边。这样就保证了每个点有唯一的后继。再由于是要求所有点都属于一个圈,也就是完美匹配,就判断一下是否满流,流入汇点的总流量是否为 n 就行了。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<queue>
 6 using namespace std;
 7 
 8 const int N=110,M=30010,NN=310,D=110,INF=(int)1e9;
 9 int n,len;
10 int last[NN],vis[NN],id[NN],pre[NN],flow[NN],d[NN];
11 struct edge{int y,fl,c,next;}e[M];
12 queue<int> q;
13 
14 int mmin(int x,int y) {return x<y?x:y;}
15 void ins(int x,int y,int fl,int c)
16 {
17     e[++len].y=y,e[len].fl=fl,e[len].c=c;
18     e[len].next=last[x],last[x]=len;
19     e[++len].y=x,e[len].fl=0,e[len].c=-c;
20     e[len].next=last[y],last[y]=len;
21 }
22 bool spfa(int st,int ed)
23 {
24     while (!q.empty()) q.pop();
25     memset(vis,0,sizeof(vis));
26     memset(d,63,sizeof(d));
27     memset(pre,0,sizeof(pre));
28     q.push(st);
29     d[st]=0,vis[st]=1,flow[st]=INF;
30     while (!q.empty())
31     {
32       int x=q.front();
33       q.pop(); vis[x]=0;
34       for (int i=last[x];i;i=e[i].next)
35       {
36         int y=e[i].y;
37         if (e[i].fl && d[x]+e[i].c<d[y])
38         {
39           d[y]=d[x]+e[i].c;
40           flow[y]=mmin(flow[x],e[i].fl);
41           id[y]=i,pre[y]=x;
42           if (!vis[y]) q.push(y),vis[y]=1;
43         }
44       }
45     }
46     return pre[ed];
47 }
48 int Max_flow(int st,int ed)
49 {
50     int sum=0,h=0;
51     while (spfa(st,ed))
52     {
53       sum+=flow[ed]*d[ed];
54       h+=flow[ed];
55       for (int i=ed;i!=st;i=pre[i])
56       {
57         e[id[i]].fl-=flow[ed];
58         e[id[i]^1].fl+=flow[ed];
59       }
60     }
61     if (h==n) return sum;
62     return 0;
63 }
64 int main()
65 {
66     while (1)
67     {
68       scanf("%d",&n);
69       if (!n) break;
70       int st=2*n+1,ed=2*n+2,x,y;
71       len=1;
72       memset(last,0,sizeof(last));
73       for (int i=1;i<=n;i++)
74       {
75         ins(st,i,1,0),ins(n+i,ed,1,0);
76         while (1)
77         {
78           scanf("%d",&x);
79           if (!x) break;
80           scanf("%d",&y);
81           ins(i,n+x,1,y);
82         }
83       }
84       int ans=Max_flow(st,ed);
85       if (!ans) printf("N\n");
86       else printf("%d\n",ans);
87     }
88     return 0;
89 }

 

转载于:https://www.cnblogs.com/konjak/p/6049884.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值