度度熊的交易计划
Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 260 Accepted Submission(s): 83
Problem Description
度度熊参与了喵哈哈村的商业大会,但是这次商业大会遇到了一个难题:
喵哈哈村以及周围的村庄可以看做是一共由n个片区,m条公路组成的地区。
由于生产能力的区别,第i个片区能够花费a[i]元生产1个商品,但是最多生产b[i]个。
同样的,由于每个片区的购买能力的区别,第i个片区也能够以c[i]的价格出售最多d[i]个物品。
由于这些因素,度度熊觉得只有合理的调动物品,才能获得最大的利益。
据测算,每一个商品运输1公里,将会花费1元。
那么喵哈哈村最多能够实现多少盈利呢?
Input
本题包含若干组测试数据。
每组测试数据包含:
第一行两个整数n,m表示喵哈哈村由n个片区、m条街道。
接下来n行,每行四个整数a[i],b[i],c[i],d[i]表示的第i个地区,能够以a[i]的价格生产,最多生产b[i]个,以c[i]的价格出售,最多出售d[i]个。
接下来m行,每行三个整数,u[i],v[i],k[i],表示该条公路连接u[i],v[i]两个片区,距离为k[i]
可能存在重边,也可能存在自环。
满足:
1<=n<=500,
1<=m<=1000,
1<=a[i],b[i],c[i],d[i],k[i]<=1000,
1<=u[i],v[i]<=n
Output
输出最多能赚多少钱。
Sample Input
2 1
5 5 6 1
3 5 7 7
1 2 1
Sample Output
23
Source
恰当的建图之后就是个裸的最小费用流(当然,由于求的是最大盈利,值乘-1进行计算)了。将每个点拆成3个,分别为: 由源点连向的点(边cost=a[i],cap=b[i]) 由第一种点(对应原图中下标设为i)连向的“入点”(对应原图中下标设为j)(cost=-(c[j]-dis[i][j]),cap=a[i])(其中dis[i][j]为i到j的最短路,事先需要floyd跑一边求一下) 由于每个点出售的数量是有限制的,故第三种点为第二种点一一对应连接的(cost=0,cap=d[i])第三种点再连向汇点。
不过需要注意的是,这样建的图并不一定是满流(因为有的地方可以不生产),故为了保证最小费用流中的满流条件,再增加一个“超级源点”、“超级汇点”,分别与原本的源点、汇点相连,并增加一条从原本的源点连向汇点的cost=0,cap=INF的边。
建完图之后直接进行最小费用流即可。
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <vector> 5 #include <set> 6 #include <map> 7 #include <string> 8 #include <cstring> 9 #include <stack> 10 #include <queue> 11 #include <cmath> 12 #include <ctime> 13 #include<bitset> 14 #include <utility> 15 using namespace std; 16 #define REP(I,N) for (I=0;I<N;I++) 17 #define rREP(I,N) for (I=N-1;I>=0;I--) 18 #define rep(I,S,N) for (I=S;I<N;I++) 19 #define rrep(I,S,N) for (I=N-1;I>=S;I--) 20 #define FOR(I,S,N) for (I=S;I<=N;I++) 21 #define rFOR(I,S,N) for (I=N;I>=S;I--) 22 #define rank rankk 23 #define DFT FFT 24 typedef unsigned long long ull; 25 typedef long long ll; 26 //const int INF=0x3f3f3f3f; 27 const ll INFF=0x3f3f3f3f3f3f3f3fll; 28 //const ll M=1e9+7; 29 const ll maxn=2e5+7; 30 //const int MAXN=1005; 31 const int MAX=1e6+5; 32 const int MAX_N=MAX; 33 //const int N=55; 34 const ll MOD=1e9+7; 35 //const double eps=0.00000001; 36 int gcd(int a,int b){return b?gcd(b,a%b):a;} 37 template<typename T>inline T abs(T a) {return a>0?a:-a;} 38 inline ll powMM(ll a,ll b,ll M){ 39 ll ret=1; 40 a%=M; 41 // b%=M; 42 while (b){ 43 if (b&1) ret=ret*a%M; 44 b>>=1; 45 a=a*a%M; 46 } 47 return ret; 48 } 49 void open() 50 { 51 freopen("t.txt","r",stdin); 52 freopen("out.txt","w",stdout); 53 } 54 55 const int MAXN = 10000; 56 const int MAXM = 1000000; 57 const int INF = 0x3f3f3f3f; 58 struct Edge 59 { 60 int to,next,cap,flow,cost; 61 }edge[MAXM]; 62 int head[MAXN],tol; 63 int pre[MAXN],dis[MAXN]; 64 bool vis[MAXN]; 65 int N;//节点总个数,节点编号从0~N-1 66 void init(int n) 67 { 68 N = n; 69 tol = 0; 70 memset(head,-1,sizeof(head)); 71 } 72 void addedge(int u,int v,int cap,int cost) 73 { 74 edge[tol].to = v; edge[tol].cap = cap; edge[tol].cost = cost; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = 0; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; 75 } 76 bool spfa(int s,int t) 77 { 78 queue<int>q; 79 for(int i = 0;i < N;i++) 80 { 81 dis[i] = INF; vis[i] = false; pre[i] = -1; 82 } 83 dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) 84 { 85 int u = q.front(); q.pop(); 86 vis[u] = false; 87 for(int i = head[u]; i != -1;i = edge[i].next) 88 { 89 int v = edge[i].to; 90 91 92 if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost ) 93 { 94 dis[v] = dis[u] + edge[i].cost; pre[v] = i; 95 if(!vis[v]) 96 { 97 vis[v] = true; q.push(v); 98 } 99 } 100 } 101 } 102 if(pre[t] == -1)return false; else return true; 103 } 104 //返回的是最大流,cost存的是最小费用 105 int minCostMaxflow(int s,int t,int &cost) 106 { 107 int flow = 0; cost = 0; while(spfa(s,t)) 108 { 109 int Min = INF; 110 for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) 111 { 112 if(Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; 113 } 114 for(int i = pre[t];i != -1;i = pre[edge[i^1].to]) 115 { 116 edge[i].flow += Min; edge[i^1].flow -= Min; 117 cost += edge[i].cost * Min; 118 } 119 flow += Min; 120 } 121 return flow; 122 } 123 int n,m; 124 int diss[505][505]; 125 int a[505],b[505],c[505],d[505]; 126 int V;//顶点数 127 void warshall_floyd() 128 { 129 for(int k=1;k<=V;k++) 130 for(int i=1;i<=V;i++) 131 for(int j=1;j<=V;j++) 132 diss[i][j]=min(diss[i][j],diss[i][k]+diss[k][j]); 133 } 134 int main() 135 { 136 while(~scanf("%d%d",&n,&m)) 137 { 138 memset(diss,-1,sizeof(diss)); 139 for(int i=1;i<=n;i++) 140 scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]); 141 for(int i=1;i<=n;i++) 142 for(int j=1;j<=n;j++) 143 diss[i][j]=(int)1e9; 144 for(int i=1;i<=n;i++) 145 diss[i][i]=0; 146 for(int i=1;i<=m;i++) 147 { 148 int x,y,z; 149 scanf("%d%d%d",&x,&y,&z); 150 if(x==y) 151 continue; 152 diss[x][y]=diss[y][x]=min(z,diss[x][y]); 153 } 154 V=n; 155 warshall_floyd(); 156 init(3*n+4); 157 for(int i=1;i<=n;i++) 158 addedge(0,i,b[i],a[i]); 159 for(int i=1;i<=n;i++) 160 { 161 for(int j=1;j<=n;j++) 162 { 163 if(diss[i][j]!=-1&&c[j]>=a[i]+diss[i][j]) 164 addedge(i,j+n,b[i],-(c[j]-diss[i][j])); 165 } 166 } 167 for(int i=1;i<=n;i++) 168 addedge(i+n,i+2*n,d[i],0); 169 for(int i=1;i<=n;i++) 170 addedge(i+2*n,3*n+1,d[i],0); 171 addedge(3*n+2,0,INF,0); 172 addedge(3*n+1,3*n+3,INF,0); 173 addedge(0,3*n+1,INF,0); 174 int co; 175 int an=minCostMaxflow(3*n+2,3*n+3,co); 176 printf("%d\n",-co); 177 } 178 }