UVALive - 6266 Admiral 费用流

 UVALive - 6266 Admiral

题意:找两条完全不相交不重复的路使得权值和最小。

思路:比赛的时候时间都卡在D题了,没有仔细的想这题,其实还是很简单的,将每个点拆开,连一条容量为1,费用为0的边,起点和终点容量为2,两点之间有边就加一条容量为1,费用为权值的边,这样跑一边费用流就可以了。

 

  1 #pragma comment(linker, "/STACK:1000000000")
  2 #include <bits/stdc++.h>
  3 #define LL long long
  4 #define INF 0x3f3f3f3f
  5 #define IN freopen("in.txt","r",stdin);
  6 #define OUT freopen("out.txt","w",stdout);
  7 using namespace std;
  8 #define MAXN 9999
  9 #define V 2005
 10 #define E 30005
 11 int vis[V];
 12 int dist[V];
 13 int pre[V];
 14 
 15 struct Edge{
 16     int u,v,c,cost,next;
 17 }edge[E];
 18 int head[V],cnt;
 19 
 20 void init(){
 21     cnt=0;
 22     memset(head,-1,sizeof(head));
 23 }
 24 void addedge(int u,int v,int c,int cost)
 25 {
 26     edge[cnt].u=u;edge[cnt].v=v;edge[cnt].cost=cost;
 27     edge[cnt].c=c;edge[cnt].next=head[u];head[u]=cnt++;
 28 
 29     edge[cnt].u=v;edge[cnt].v=u;edge[cnt].cost=-cost;
 30     edge[cnt].c=0;edge[cnt].next=head[v];head[v]=cnt++;
 31 }
 32 
 33 bool spfa(int begin,int end){
 34     int u,v;
 35     queue<int> q;
 36     for(int i=0;i<=end+2;i++){
 37         pre[i] = -1;
 38         vis[i] = 0;
 39         dist[i] = INF;
 40     }
 41     vis[begin]=1;
 42     dist[begin]=0;
 43     q.push(begin);
 44     while(!q.empty()){
 45         u=q.front();
 46         q.pop();
 47         vis[u]=0;
 48         for(int i=head[u];i!=-1;i=edge[i].next){
 49             if(edge[i].c>0){
 50                 v=edge[i].v;
 51                 if(dist[v]>dist[u]+edge[i].cost){
 52                     dist[v]=dist[u]+edge[i].cost;
 53                     pre[v]=i;
 54                     if(!vis[v]){
 55                         vis[v]=true;
 56                         q.push(v);
 57                     }
 58                 }
 59             }
 60         }
 61     }
 62     return dist[end] != INF;
 63 }
 64 
 65 int MCMF(int begin,int end){
 66     int ans=0,flow;
 67     int flow_sum=0;
 68     while(spfa(begin,end)){
 69         flow=INF;
 70         for(int i=pre[end];i!=-1;i=pre[edge[i].u])
 71             if(edge[i].c<flow)
 72                 flow=edge[i].c;
 73         for(int i=pre[end];i!=-1;i=pre[edge[i].u]){
 74             edge[i].c-=flow;
 75             edge[i^1].c+=flow;
 76         }
 77         ans+=dist[end];
 78         flow_sum += flow;
 79     }
 80     //cout << flow_sum << endl;
 81     return ans;
 82 }
 83 
 84 int main()
 85 {
 86     //IN;
 87     int n, m, x, y, z;
 88     while(~scanf("%d%d", &n, &m)){
 89         init();
 90         int s = 1, t = 2 * n;
 91         for(int i = 2; i < n; i++){
 92             addedge(i, i + n, 1, 0);
 93         }
 94         addedge(1, n + 1, 2, 0);
 95         addedge(n, n << 1, 2, 0);
 96         for(int i = 1; i <= m; i++){
 97             scanf("%d%d%d", &x, &y, &z);
 98             addedge(x + n, y, 1, z);
 99         }
100         int ans = MCMF(s, t);
101         printf("%d\n", ans);
102     }
103     return 0;
104 }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值