BZOJ 2324 营救皮卡丘

http://www.lydsy.com/JudgeOnline/problem.php?id=2324

思路:最小费用最大流

考虑设数组d[k][i][j],代表只用前k个城市,i到j的最短路

然后可以这样建图

S->0 流量为K,费用为0

i->i+n 流量为inf,费用为0

i+n->T 流量为1

i+n->j 流量为inf,费用为d[j][i][j]

S->i  流量为1,费用为0 代表如果一个人到了i城市,它可以继续走,从而续出来的一个新流量。

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #define inf 0x7fffffff
 7 int d[205][205][205],a[205][205],K;
 8 int tot,go[200005],next[200005],first[200005],cost[200005],flow[200005];
 9 int op[200005],dis[200005],c[200005],vis[200005],edge[200005],from[200005];
10 int S,T,n,m,ans;
11 int read(){
12     char ch=getchar();int t=0,f=1;
13     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
14     while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();}
15     return t*f;
16 }
17 void insert(int x,int y,int z,int l){
18     tot++;
19     go[tot]=y;
20     next[tot]=first[x];
21     first[x]=tot;
22     flow[tot]=z;
23     cost[tot]=l;
24 }
25 void add(int x,int y,int z,int l){
26     insert(x,y,z,l);op[tot]=tot+1;
27     insert(y,x,0,-l);op[tot]=tot-1;
28 }
29 bool spfa(){
30     for (int i=0;i<=T;i++)
31      dis[i]=0x3f3f3f3f,vis[i]=0;
32     int h=1,t=1;c[1]=S;vis[S]=1;dis[S]=0;
33     while (h<=t){
34         int now=c[h++];
35         for (int i=first[now];i;i=next[i]){
36             int pur=go[i];
37             if (dis[pur]>dis[now]+cost[i]&&flow[i]){
38                 dis[pur]=dis[now]+cost[i];
39                 edge[pur]=i;
40                 from[pur]=now;
41                 if (vis[pur]) continue;
42                 vis[pur]=1;
43                 c[++t]=pur;
44             }
45         }
46         vis[now]=0;
47     }
48     return dis[T]!=0x3f3f3f3f;
49 }
50 void updata(){
51     int mn=0x7ffffff;
52     for (int i=T;i!=S;i=from[i]){
53         mn=std::min(mn,flow[edge[i]]);
54     }
55     for (int i=T;i!=S;i=from[i]){
56         ans+=mn*cost[edge[i]];
57         flow[edge[i]]-=mn;
58         flow[op[edge[i]]]+=mn;
59     }
60 }
61 int main(){
62     n=read();m=read();K=read();
63     for (int i=0;i<=n;i++)
64      for (int j=0;j<=n;j++)
65       if (i!=j){
66             a[i][j]=0x3f3f3f3f;
67       }else
68             a[i][j]=0;
69     for (int i=1;i<=m;i++){
70         int u=read(),v=read(),w=read();
71         a[u][v]=std::min(a[u][v],w);
72         a[v][u]=std::min(a[v][u],w);
73     }
74     for (int k=0;k<=n;k++){
75         for (int i=0;i<=n;i++)
76          for (int j=0;j<=n;j++)
77           a[i][j]=std::min(a[i][k]+a[k][j],a[i][j]);
78         for (int i=0;i<=n;i++)
79          for (int j=0;j<=n;j++)
80           d[k][i][j]=a[i][j];  
81     }
82     S=2*n+2;T=S+1;
83     add(S,0,K,0);
84     for (int i=0;i<=n;i++)
85      add(i,i+n+1,inf,0);
86     for (int i=0;i<=n;i++)
87      add(i,T,1,0);
88     for (int i=0;i<=n;i++)
89      add(S,i+n+1,1,0);
90     for (int i=0;i<=n;i++)
91      for (int j=i+1;j<=n;j++)
92       if (d[j][i][j]<0x3f3f3f3f)
93       add(i+n+1,j,inf,d[j][i][j]);
94     while (spfa()) updata();
95     printf("%d\n",ans);      
96 }

 

转载于:https://www.cnblogs.com/qzqzgfy/p/5615310.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值