http://fastvj.rainng.com/contest/236779#problem/Gnode
Description:ios
n 行 m 列數組
給你行和 與 列和函數
而後有Q個限制,表示特定單元格元素大小的範圍,最後問你可行的矩陣值spa
Solution:
有源匯上下界最大流問題,初始源點 連 行和流量是該行對應得行和,而後列連初始匯點,容量爲列的列和,詳細的限制,對應於行列之間,由於我最後要輸出一個矩陣,因此n * m每一條邊都要連接最後,手動連一條 t s inf的邊,變成無源匯有上下界可行流問題,而後拆邊,把對應邊的流量,放到數組裏,輸出就好啦blog
Code:ip
前面比較基礎的Dinic,數據操做函數,加邊操做string
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #define inf (1 << 28) using namespace std; const int maxn = 25; const int maxm = 210; const int mn = 505; const int mm = 440020; struct node{ int to,val,pre,lid; }e[mm]; int id[mn],cnt=0; int cur[mn]; int flor[mn]; int upflow[mn]; int lowf[maxm][maxn]; int upf[maxm][maxn]; int out[maxm][maxn]; void init() { memset(id,-1,sizeof(id)); memset(upflow,0,sizeof(upflow)); cnt = 0; } void add(int from,int to,int val,int lid) { e[cnt].to = to; e[cnt].val = val; e[cnt].lid = lid; e[cnt].pre = id[from]; id[from] = cnt++; swap(from,to); e[cnt].to = to; e[cnt].val = 0; e[cnt].lid = lid; e[cnt].pre = id[from]; id[from] = cnt++; } void addflow(int from,int to,int low,int up,int lid) { upflow[from] -= low; upflow[to] += low; add(from,to,up-low,lid); } bool bfs(int s,int t) { memset(flor,0,sizeof(flor)); flor[s] = 1; queue<int> q; while(q.size())q.pop(); q.push(s); while(q.size()) { int now = q.front(); q.pop(); for(int i = id[now];~i;i = e[i].pre) { int to = e[i].to; int val = e[i].val; if(val > 0 && flor[to] == 0) { flor[to] = flor[now] + 1; q.push(to); if(to == t) return true; } } } return false; } int dfs(int s,int t,int value) { if(s == t || value == 0)return value; int ret = value,a; for(int &i = cur[s];~i;i = e[i].pre) { int val = e[i].val; int to = e[i].to; if(flor[to] == flor[s] + 1 && (a = dfs(to,t,min(ret,val)))) { e[i].val -= a; e[i^1].val += a; ret -= a; if(ret == 0)break; } } if(ret == value)flor[s] = 0; return value - ret; } int Dinic(int s,int t) { int ret = 0; while(bfs(s,t)) { memcpy(cur,id,sizeof(id)); ret += dfs(s,t,inf); } return ret; } void addlimit(int i,int j,char op,int lim) { if(op == '=') { upf[i][j] = lowf[i][j] = lim; } else if(op == '>') { lowf[i][j] = max(lowf[i][j],lim+1); } else { upf[i][j] = min(upf[i][j],lim-1); } }
而後根據輸入一點點的加邊,這是行和和列和對應的邊it
scanf("%d%d",&n,&m); s = 0; t = n + m + 1; ss = t + 1; tt = ss + 1; int lsum; for(int i = 1;i <= n;++i) { scanf("%d",&lsum); addflow(s,i,lsum,lsum,0); } for(int i = 1;i <= m;++i) { scanf("%d",&lsum); addflow(n + i,t,lsum,lsum,0); } int limitnum;
而後根據題目中給出的限制條件,填充上下界數組io
scanf("%d",&limitnum); for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) { lowf[i][j] = 0; upf[i][j] = inf; } } int row,col,lim; char op; for(int i = 1;i <= limitnum;++i) { scanf("%d %d %c %d",&row,&col,&op,&lim); if(row == 0 && col == 0) { for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) { addlimit(i,j,op,lim); } } } else if(row == 0) { for(int i = 1;i <= n;++i) { addlimit(i,col,op,lim); } } else if(col == 0) { for(int i = 1;i <= m;++i) { addlimit(row,i,op,lim); } } else { addlimit(row,col,op,lim); } }
根據上下界數組,添加有上下界邊
int tot = 0; for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) { addflow(i,n+j,lowf[i][j],upf[i][j],++tot); } }
加邊完成後,轉化爲無源匯有上下界可行流 ———— 循環流
add(t,s,inf,0); int sum = 0; for(int i = s;i <= t;++i) { if(upflow[i] < 0) { add(i,tt,-upflow[i],0); } else { sum += upflow[i]; add(ss,i,upflow[i],0); } }
跑DIinc,若是存在可行流的話
就輸出叭~~
for(int now = n+1;now <= n + m;++now) { for(int i = id[now];~i;i = e[i].pre) { int to = e[i].to; int lid = e[i].lid; if(lid == 0 || i % 2 == 0)continue; out[to][now-n] = lowf[to][now-n] + e[i].val; } } for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) { if(j == 1) printf("%d",out[i][j]); else printf(" %d",out[i][j]); } printf("\n"); }
完整代碼
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #define inf (1 << 28) using namespace std; const int maxn = 25; const int maxm = 210; const int mn = 505; const int mm = 440020; struct node{ int to,val,pre,lid; }e[mm]; int id[mn],cnt=0; int cur[mn]; int flor[mn]; int upflow[mn]; int lowf[maxm][maxn]; int upf[maxm][maxn]; int out[maxm][maxn]; void init() { memset(id,-1,sizeof(id)); memset(upflow,0,sizeof(upflow)); cnt = 0; } void add(int from,int to,int val,int lid) { e[cnt].to = to; e[cnt].val = val; e[cnt].lid = lid; e[cnt].pre = id[from]; id[from] = cnt++; swap(from,to); e[cnt].to = to; e[cnt].val = 0; e[cnt].lid = lid; e[cnt].pre = id[from]; id[from] = cnt++; } void addflow(int from,int to,int low,int up,int lid) { upflow[from] -= low; upflow[to] += low; add(from,to,up-low,lid); } bool bfs(int s,int t) { memset(flor,0,sizeof(flor)); flor[s] = 1; queue<int> q; while(q.size())q.pop(); q.push(s); while(q.size()) { int now = q.front(); q.pop(); for(int i = id[now];~i;i = e[i].pre) { int to = e[i].to; int val = e[i].val; if(val > 0 && flor[to] == 0) { flor[to] = flor[now] + 1; q.push(to); if(to == t) return true; } } } return false; } int dfs(int s,int t,int value) { if(s == t || value == 0)return value; int ret = value,a; for(int &i = cur[s];~i;i = e[i].pre) { int val = e[i].val; int to = e[i].to; if(flor[to] == flor[s] + 1 && (a = dfs(to,t,min(ret,val)))) { e[i].val -= a; e[i^1].val += a; ret -= a; if(ret == 0)break; } } if(ret == value)flor[s] = 0; return value - ret; } int Dinic(int s,int t) { int ret = 0; while(bfs(s,t)) { memcpy(cur,id,sizeof(id)); ret += dfs(s,t,inf); } return ret; } void addlimit(int i,int j,char op,int lim) { if(op == '=') { upf[i][j] = lowf[i][j] = lim; } else if(op == '>') { lowf[i][j] = max(lowf[i][j],lim+1); } else { upf[i][j] = min(upf[i][j],lim-1); } } int main() { int T; scanf("%d",&T); int n,m,s,t,ss,tt; while(T--) { init(); scanf("%d%d",&n,&m); s = 0; t = n + m + 1; ss = t + 1; tt = ss + 1; int lsum; for(int i = 1;i <= n;++i) { scanf("%d",&lsum); addflow(s,i,lsum,lsum,0); } for(int i = 1;i <= m;++i) { scanf("%d",&lsum); addflow(n + i,t,lsum,lsum,0); } int limitnum; scanf("%d",&limitnum); for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) { lowf[i][j] = 0; upf[i][j] = inf; } } int row,col,lim; char op; for(int i = 1;i <= limitnum;++i) { scanf("%d %d %c %d",&row,&col,&op,&lim); if(row == 0 && col == 0) { for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) { addlimit(i,j,op,lim); } } } else if(row == 0) { for(int i = 1;i <= n;++i) { addlimit(i,col,op,lim); } } else if(col == 0) { for(int i = 1;i <= m;++i) { addlimit(row,i,op,lim); } } else { addlimit(row,col,op,lim); } } int tot = 0; for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) { addflow(i,n+j,lowf[i][j],upf[i][j],++tot); } } add(t,s,inf,0); int sum = 0; for(int i = s;i <= t;++i) { if(upflow[i] < 0) { add(i,tt,-upflow[i],0); } else { sum += upflow[i]; add(ss,i,upflow[i],0); } } if(Dinic(ss,tt) == sum) { for(int now = n+1;now <= n + m;++now) { for(int i = id[now];~i;i = e[i].pre) { int to = e[i].to; int lid = e[i].lid; if(lid == 0 || i % 2 == 0)continue; out[to][now-n] = lowf[to][now-n] + e[i].val; } } for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) { if(j == 1) printf("%d",out[i][j]); else printf(" %d",out[i][j]); } printf("\n"); } } else { printf("IMPOSSIBLE\n"); } if(T)printf("\n"); } return 0; }