标签:意思 lld ref 有意思 scan blog 题解 ini void
题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=2543
这个题目挺有意思。
自己扣了一会儿,发现图挺好建,就把(u,v,f,w) 拆成(u,v,f,0)和(u,v,INF,w)就好了。但是在枚举石头时,我想的是二分石头个数,就需要每次重新建图,把边的信息提前保存下来,发现有点麻烦。
看题解说,利用连续最短路算法,每次找一条最小费用路并尽可能多的增广,直到剩余钱数不够再运一个石头为止。就是直接在模板里面改,太方便了。
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 #include <vector>
5 #include <queue>
6 #include <algorithm>
7 using namespace std;
8 const int maxn = 2e3;
9 const int INF = 1e9;
10 int vis[maxn],dist[maxn];
11 int tot,head[maxn];
12 int pv[maxn],pe[maxn];
13 typedef long long ll;
14 struct edge
15 {
16 int to,pre,cap,cost;
17 }e[100000];
18 void init()
19 {
20 tot = 0;
21 memset(head,-1,sizeof(head));
22 }
23 void add(int from,int to,int cap,int cost)
24 {
25 e[tot].pre = head[from];
26 e[tot].to = to;
27 e[tot].cap = cap;
28 e[tot].cost = cost;
29 head[from] = tot++;
30 }
31 void addedge(int from,int to,int cap,int cost)
32 {
33 add(from,to,cap,cost);
34 add(to,from,0,-cost);
35 }
36 int n,m;
37 ll c,p;
38 int ans = 0;
39 int min_cost_flow(int s,int t,int f,int& max_flow)
40 {
41 int ret = 0;
42 while(f>0)
43 {
44 memset(vis,0,sizeof(vis));
45 for(int i=0;i<maxn;i++) dist[i] = INF;
46 dist[s] = 0;
47 queue<int> q;
48 q.push(s);
49 while(!q.empty())
50 {
51 int v = q.front(); q.pop();
52 vis[v] = 0;
53 for(int i=head[v];i>=0;i=e[i].pre)
54 {
55 int to = e[i].to,cap = e[i].cap,cost = e[i].cost;
56 if(cap>0&&dist[to]>dist[v]+cost)
57 {
58 pv[to] = v,pe[to] = i;
59 dist[to] = dist[v] + cost;
60 if(!vis[to]) q.push(to);
61 vis[to] = 1;
62 }
63 }
64 }
65 if(dist[t]==INF) return ret;
66 ///当所有边的流量都流净后,即没有残余网络,返回。
67 int d = f;
68 for(int v=t;v!=s;v=pv[v])
69 {
70 d = min(d,e[pe[v]].cap);
71 }
72 f -= d;
73 max_flow += d;
74 ret += d*dist[t]; ///走一单位就消耗dist[t]
75 for(int v=t;v!=s;v=pv[v])
76 {
77 e[pe[v]].cap -= d;
78 e[pe[v]^1].cap += d;
79 }
80
81 ///最有意思,在模板里面修改,利用增广路不断去减少钱数
82 if(c>=((ll)d*p+(ll)d*dist[t]))
83 {
84 c -= ((ll)d*p+(ll)d*dist[t]);
85 ans += d;
86 }
87 else
88 {
89 ans += (c/((ll)dist[t]+(ll)p)); ///算算单独能运几块石头
90 break;
91 }
92 }
93 return ret;
94 }
95 int main()
96 {
97 int T;scanf("%d",&T);
98 while(T--)
99 {
100 init(); //别忘写
101 scanf("%d %d %lld %lld",&n,&m,&c,&p);
102 int u,v,f,w;
103 for(int i=1;i<=m;i++)
104 {
105 scanf("%d %d %d %d",&u,&v,&f,&w);
106 addedge(u,v,f,0);
107 addedge(v,u,f,0);
108 addedge(u,v,INF,w);
109 addedge(v,u,INF,w);
110 }
111 int max_flow = 0;
112 ans = 0;
113 min_cost_flow(0,1,INF,max_flow);
114 printf("%d\n",ans);
115 }
116 return 0;
117 }
标签:意思 lld ref 有意思 scan blog 题解 ini void
原文地址:http://www.cnblogs.com/littlepear/p/7614324.html