Hdu--4780(费用流,上下界)
2015-02-23 16:11:16
思路:一道有上下界的费用流。
建图:比较巧妙,根据题意思考,机器只会影响其第一个加工的糖果,而之后加工的糖果只与其之气加工的糖果有关,与机器无关。
因此,我们建立一个超级源点,与各个机器连边,容量1费用0;同理再建立超级汇点,各个机器与超级汇点连边,这个很容易落掉。
(因为某些机器可以不用,所以直接流到超级汇点而不经过糖果。如果不建这条边,求最大流时,会使得某些不合算的机器也被用来加工糖果。)
然后,因为每个糖果只有一颗,所以我们将糖果拆点,连边,容量1费用-INF(为了保证这颗糖果必须加工),再在机器与糖果之间建边,容量1,费用要通过时间来计算。
最后,糖果之间建边,容量1,费用是转换费用。
建完图后跑一遍最小费用最大流,然后将答案加上 n × INF(补偿回来),如果答案>INF,说明不是每颗糖果都加工过,输出-1。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=1;i<=(n);++i) 17 #define REV(i,n) for(int i=(n);i>=1;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 #define X first 23 #define Y second 24 25 typedef long long ll; 26 typedef pair<int,int> pii; 27 const ll INF = (1 << 28); 28 const int MAXN = 510; 29 30 int N,M,K; 31 int C[MAXN][MAXN],D[MAXN][MAXN],E[MAXN][MAXN],F[MAXN][MAXN]; 32 int st[MAXN],ed[MAXN]; 33 34 struct edge{ 35 int v,next; 36 ll cost; 37 int cp; 38 }; 39 40 inline int Read(){ 41 int x = 0;char ch = getchar(); 42 while(ch < '0' || ch > '9') ch = getchar(); 43 while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} 44 return x; 45 } 46 47 struct MCMF{ 48 edge e[MAXN * MAXN * 2]; 49 int sou,sin; 50 int first[MAXN],ecnt; 51 ll dis[MAXN]; 52 int prev[MAXN],pree[MAXN],inq[MAXN]; 53 void Init(){ 54 MEM(first,-1); 55 ecnt = 0; 56 } 57 void Add_edge(int u,int v,int cap,int fee){ 58 e[++ecnt].next = first[u]; 59 e[ecnt].v = v; 60 e[ecnt].cp = cap; 61 e[ecnt].cost = fee; 62 first[u] = ecnt; 63 64 e[++ecnt].next = first[v]; 65 e[ecnt].v = u; 66 e[ecnt].cp = 0; 67 e[ecnt].cost = -fee; 68 first[v] = ecnt; 69 } 70 bool Spfa(){ 71 fill(dis,dis + MAXN,INF); 72 dis[sou] = 0; 73 MEM(prev,-1),MEM(inq,0); 74 queue<int> Q; 75 while(!Q.empty()) Q.pop(); 76 Q.push(0); 77 while(!Q.empty()){ 78 int x = Q.front(); Q.pop(); 79 inq[x] = 0; 80 for(int i = first[x]; ~i; i = e[i].next){ 81 if(e[i].cp <= 0) continue; 82 int v = e[i].v; 83 if(dis[x] + e[i].cost < dis[v]){ 84 dis[v] = dis[x] + e[i].cost; 85 prev[v] = x; 86 pree[v] = i; 87 if(inq[v] == 0){ 88 inq[v] = 1; 89 Q.push(v); 90 } 91 } 92 } 93 } 94 return prev[sin] != -1; 95 } 96 ll Solve(){ 97 ll min_cost = 0; 98 while(Spfa()){ 99 for(int i = sin; i != sou; i = prev[i]){ 100 int id = pree[i]; 101 e[id].cp--; 102 e[((id - 1) ^ 1) + 1].cp++; 103 } 104 min_cost += dis[sin]; 105 } 106 return min_cost; 107 } 108 }Nat; 109 110 int main(){ 111 while(scanf("%d%d%d",&N,&M,&K) != EOF,N + M + K){ 112 Nat.Init(); 113 REP(i,N) st[i] = Read(),ed[i] = Read(); 114 REP(i,N) REP(j,M) C[i][j] = Read(); //init time 115 REP(i,N) REP(j,M) D[i][j] = Read(); //init cost 116 REP(i,N) REP(j,N) E[i][j] = Read(); //change time 117 REP(i,N) REP(j,N) F[i][j] = Read(); //change cost 118 Nat.sou = 0; //source : 0 119 //machine : 1 ~ M , candy(1) : M + 1 ~ M + N , candy(2) : M + N + 1 ~ M + 2 * N 120 Nat.sin = M + 2 * N + 1; //sin : M + 2 * N + 1 121 REP(i,M){ 122 Nat.Add_edge(Nat.sou,i,1,0); //source - machines 123 Nat.Add_edge(i,Nat.sin,1,0); //machines - sink 124 } 125 REP(i,N){ 126 Nat.Add_edge(M + i,M + N + i,1,-INF); //candy(1) - candy(2) 127 Nat.Add_edge(M + N + i,Nat.sin,1,0); //candy(2) - sink 128 } 129 REP(i,N) REP(j,M){ //candy(1)[i] , machine[j] 130 if(C[i][j] >= ed[i]) continue; 131 int add_cost = K * (max(C[i][j],st[i]) - st[i]); 132 Nat.Add_edge(j,M + i,1,D[i][j] + add_cost); 133 } 134 REP(i,N) REP(j,N) if(i != j){ //candy(2)[i] - candy(1)[j] 135 if(ed[i] + E[i][j] >= ed[j]) continue; 136 int add_cost = K * (max(ed[i] + E[i][j],st[j]) - st[j]); 137 Nat.Add_edge(M + N + i,M + j,1,F[i][j] + add_cost); 138 } 139 ll ans = Nat.Solve(); 140 ans += N * INF; 141 if(ans >= INF) printf("-1\n"); 142 else printf("%d\n",ans); 143 } 144 return 0; 145 }