Luogu1006 傳紙條 與 Luogu P2045方格取數加強版 (費用流)
阿新 • • 發佈:2019-02-09
min cto cpp ++ 是否 putc iostream stream std 表示第一個人走到i,j第二個人走到k,l兩人不相交的最大價值.
轉移的時候只要判斷一下路徑是否相交就ok了。
沒有完全利用好性質
用性質2:設狀態\(f[k][i][j]\)表示第一個人和第二個人都走了k步,第一個人到了\((i,k?j)\),第二個人到了\((j,k?j)\)的最大價值.
也就是傳紙條
第三問
考慮費用流。
開一個源點連向\((1,1)\),流量為\(k\),費用為\(0\)。
對於一個點,先拆點。
一條是流量為\(inf\),費用為\(0\),另外一條是流量\(inf\),費用為\(a\)
然後向下和右連邊.
Luogu1006 傳紙條 與 Luogu P2045方格取數加強版
其實就是這幾道題
在一個有m*n 個方格的棋盤中
每個方格中有一個正整數
現要從在方格中從左上角到右下角取數,只能向右或向下走
每走到一個格子就可以把這個位置上的數取走(下次經過就沒有了)
1.讓你走1次,求取出的數的總和最大是多少
2.讓你走2次,求取出的數的總和最大是多少
3.讓你走k次,求取出的數的總和最大是多少
對於第一問,十分顯然.
設\(f[i][j]\)表示\(i\)行\(j\)列的最大價值,轉移即可。
第二問,較上一題有些難度。
考慮有性質:
1,如果兩人相遇,那麽一定不是最優的
2.走n+m步數.
用性質1:設狀態\(f[i][j][k][l]\)
轉移的時候只要判斷一下路徑是否相交就ok了。
沒有完全利用好性質
用性質2:設狀態\(f[k][i][j]\)表示第一個人和第二個人都走了k步,第一個人到了\((i,k?j)\),第二個人到了\((j,k?j)\)的最大價值.
也就是傳紙條
第三問
考慮費用流。
開一個源點連向\((1,1)\),流量為\(k\),費用為\(0\)。
對於一個點,先拆點。
一條是流量為\(inf\),費用為\(0\),另外一條是流量\(inf\),費用為\(a\)
然後向下和右連邊.
/*header*/ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <cmath> #include <map> #include <queue> #define gc getchar() #define pc putchar #define ll long long #define mk make_pair #define fi first #define se second using std::min; using std::max; using std::swap; const int inf = 0x3f3f3f3f; inline int gi() { int x = 0,f = 1;char c = gc; while(c < '0' || c > '9') {if(c == '-')f = -1;c = gc;} while(c >= '0' && c <= '9') {x = x * 10 + c - '0';c = gc;}return x * f; } const int maxN = 5000 + 7; const int maxM = 100000 + 7 ; using namespace std; int n, m, s, t, ans, maxflow, k; int head[maxN]; struct Node{ int u,v,flow,spend,nex; }Map[maxM]; int dis[maxN],vis[maxN],num,path[maxN]; void init() { s = n * n * 2 + 1; t = s + 1; num = -1; memset(head,-1,sizeof(head)); return; } void add_Node(int u,int v,int w,int spend) { Map[++ num] = (Node) {u , v, w, spend, head[u]};head[u] = num; Map[++ num] = (Node) {v , u, 0, -spend, head[v]};head[v] = num; return ; } bool spfa() { queue<int>q; q.push(s); memset(dis,0x3f,sizeof(dis)); memset(path,0,sizeof(path)); dis[s] = 0; vis[s] = true; while(!q.empty()) { int p = q.front();q.pop(); vis[p] = false; for(int i = head[p];i != -1;i = Map[i].nex) { int v = Map[i].v; if(dis[v] > dis[p] + Map[i].spend && Map[i].flow) { dis[v] = dis[p] + Map[i].spend; path[v] = i; if(!vis[v]) { q.push(v); vis[v] = true; } } } } if(dis[t] == 0x3f3f3f3f) return false; return true; } int min(int a,int b) {return a > b ? b : a ;} void f() { int mn = 0x7fffffff; for(int i = t;i != s;i = Map[path[i]].u) mn = min(mn,Map[path[i]].flow); ans += mn; for(int i = t;i != s;i = Map[path[i]].u) { Map[path[i]].flow -= mn; Map[path[i] ^ 1].flow += mn; maxflow += mn * Map[path[i]].spend; } } void EK() { while(spfa()) f(); printf("%d",-maxflow); return ; } int a[57][57]; int main() { n = gi();int k = gi(); init(); for(int i = 1;i <= n;++ i) for(int j = 1;j <= n;++ j) a[i][j] = gi(); for(int i = 1;i <= n;++ i) for(int j = 1;j <= n;++ j) add_Node((i - 1) * n + j, (i - 1) * n + j + n * n, inf, 0) , add_Node((i - 1) * n + j, (i - 1) * n + j + n * n, 1, - a[i][j]); add_Node(s , 1, k, 0); for(int i = 1;i <= n;++ i) { for(int j = 1;j <= n;++ j) { if(i < n) add_Node((i - 1) * n + j + n * n , i * n + j, inf, 0); if(j < n) add_Node((i - 1) * n + j + n * n , (i - 1) * n + j + 1, inf, 0); } } add_Node(2 * n * n , t, k, 0); EK(); return 0; }
Luogu1006 傳紙條 與 Luogu P2045方格取數加強版 (費用流)