1. 程式人生 > >poj 3422 洛谷P2045 K取方格數(方格取數加強版)

poj 3422 洛谷P2045 K取方格數(方格取數加強版)

open output bsp pac tput ons upd continue tdi

Description:

給出一個n*n的矩陣,每一格有一個非負整數Aij,(Aij <= 1000)現在從(1,1)出發,可以往右或者往下走,最後到達(n,n),每達到一格,把該格子的數取出來,該格子的數就變成0,這樣一共走K次,現在要求K次所達到的方格的數的和最大

Input:

第一行兩個數n,k(1<=n<=50, 0<=k<=10)

接下來n行,每行n個數,分別表示矩陣的每個格子的數

Output:

一個數,為最大和

思路:仍舊是拆點 因為每個點都有一個限制K和一個價值V 所以將一個點拆成兩個點,對相鄰的點連兩條邊,一條費用為V,限制為1, 一條費用為0,限制為K - 1。然後跑個最大費用最大流即可

技術分享圖片
#include<iostream>
#include<cstring>
#include<queue> 
using namespace std;
const int N = 50100, M = 2000100;
int d[N], incf[N], pre[N], n, k, s, t, maxflow, ans;
bool vis[N];

int head[N],now;
struct edges{
    int to,next,lim,w;
}edge[N<<1];
void add(int x,int y,int
z,int c){ edge[++now] = {y,head[x],z,c}; head[x] = now; edge[++now] = {x,head[y],0,-c}; head[y] = now; } int id(int i,int j,int k){ return (i - 1)*n + j + k * n * n;} bool spfa(){ queue<int> q; memset(d,0xcf,sizeof(d)); memset(vis,0,sizeof(vis)); q.push(s); d[s]
= 0; vis[s] = 1; incf[s] = 1e9; while(!q.empty()){ int x = q.front(); vis[x] = 0; q.pop(); for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(!edge[i].lim) continue; if(d[v] < d[x] + edge[i].w){ d[v] = d[x] + edge[i].w; incf[v] = min(incf[x], edge[i].lim); pre[v] = i; if(!vis[v]) vis[v] = 1, q.push(v); } } } if(d[t] == 0xcfcfcfcf) return 0; return 1; } void update(){ int x = t; while(x != s){ int i = pre[x]; edge[i].lim -= incf[t]; edge[i ^ 1].lim += incf[t]; x = edge[i ^ 1].to; } maxflow += incf[t]; ans += d[t] * incf[t]; } int main(){ ios::sync_with_stdio(false); cin>>n>>k; s = 1, t = 2*n*n; now = 1; int x; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++){ cin>>x; add(id(i,j,0),id(i,j,1),1,x); add(id(i,j,0),id(i,j,1),k - 1,0); if(j < n) add(id(i,j,1),id(i,j+1,0),k,0); if(i < n) add(id(i,j,1),id(i+1,j,0),k,0); } while(spfa()) update(); cout<<ans<<endl; return 0; }
View Code

poj 3422 洛谷P2045 K取方格數(方格取數加強版)