Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 13531 | Accepted: 4635 |
Description
Input
Output
Sample Input
1 3 3 1 1 1 0 1 1 1 2 2 1 0 1 1 2 3 1 1 1 2 1 1 1 1 1 3 2 20 0 0 0
Sample Output
4 -1
给出的物品的种类太多,不同的供应商对不同的店家供应不同的货物的花费不同,这样是同一个图中的边太多,直接建图会超时,所以,对每一种货物分别建图,求出每一种的货物的最小花费,得到最终的花费
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; #define maxn 60 #define INF 0x3f3f3f3f struct node { int v , w , s ; int next ; } p[100000]; int nk[maxn][maxn] , mk[maxn][maxn] , cnt ;//nk存储不同的店家对不同货物的需求,mk,不同的供应商对不同货物的供应量 int head[maxn<<2] , vis[maxn<<2] , dis[maxn<<2] , pre[maxn<<2] ; queue <int> q ; void add(int u,int v,int w,int s) { p[cnt].v = v ; p[cnt].w = w ; p[cnt].s = s ; p[cnt].next = head[u] ; head[u] = cnt++ ; p[cnt].v = u ; p[cnt].w = 0 ; p[cnt].s = -s ; p[cnt].next = head[v] ; head[v] = cnt++ ; } int spfa(int s,int t) { int u , v , i ; memset(dis,INF,sizeof(dis)); vis[s] = 1 ; dis[s] = 0 ; pre[s] = pre[t] = -1 ; while( !q.empty() ) q.pop(); q.push(s); while( !q.empty() ) { u = q.front(); q.pop(); vis[u] = 0 ; for(i = head[u] ; i != -1 ; i = p[i].next) { v= p[i].v ; if( p[i].w && dis[v] > dis[u] + p[i].s ) { dis[v] = dis[u] + p[i].s ; pre[v] = i ; if( !vis[v] ) { vis[v] = 1 ; q.push(v); } } } } if( pre[t] == -1 ) return 0; return 1 ; } int f(int s,int t,int k) { int ans_s = 0 , ans_w = 0 , min1 , i ;//ans_s存储最小花费,ans_w存储一共的流量 memset(vis,0,sizeof(vis)); memset(pre,-1,sizeof(pre)); while( spfa(s,t) ) { min1 = INF ; for(i = pre[t] ; i != -1 ; i = pre[ p[i^1].v ]) if( p[i].w < min1 ) min1 = p[i].w ; for(i = pre[t] ; i != -1 ; i = pre[ p[i^1].v ]) { p[i].w -= min1 ; p[i^1].w += min1 ; ans_s += min1*p[i].s ; } ans_w += min1 ; } if(ans_w == nk[0][k]) return ans_s ; return -1; } int main() { int i , j , n , m , kk , k , x , ans , flag ;//输入很复杂,尤其是不同的供应商对不同的店家供应不同的货物有不同的价格。 while(scanf("%d %d %d", &n, &m, &k) && n+m+k != 0) { /*建图方式,对每种货物分别建图,对于第ki种货物的建图:由源点到每个供应商(容量是供应的货物的量,花费是0),由供应商到店家(容量是INF,花费是供应ki货物的价格) ,有店家到汇点建图(容量是店家需要的货物的量,花费是0)*/ memset(nk,0,sizeof(nk)); for(i = 1 ; i <= n ; i++) for(j = 1 ; j <= k ; j++) { scanf("%d", &nk[i][j]); nk[0][j] += nk[i][j] ;//nk[0][]储存下一共需要第j样货物的数量 } for(i = 1 ; i <= m ; i++) for(j = 1 ; j <= k ; j++) scanf("%d", &mk[i][j]); ans = flag = 0 ;//flag判断之前的货物是不是都可以供应足够,如果不够,不用向下在计算。 for(kk = 1 ; kk <= k ; kk++) { cnt = 0 ; memset(head,-1,sizeof(head)); for(i = 1 ; i <= m ; i++) add(0,i,mk[i][kk],0); for(i = 1 ; i <= n ; i++) add(m+i,m+n+1,nk[i][kk],0); for(i = 1 ; i <= n ; i++) for(j = 1 ; j <= m ; j++) { scanf("%d", &x); add(j,m+i,INF,x); } if(flag != -1) { flag = f(0,n+m+1,kk); if(flag != -1) ans += flag ; } } if(flag == -1) printf("-1\n"); else printf("%d\n", ans); } return 0; }