1. 程式人生 > >P2045 方格取數加強版

P2045 方格取數加強版

技術分享 bsp size ima out int def string spfa

將點拆成兩條邊,一條邊的容量是1,費用是a[i],一條邊的容量是K-1,費用是0.這樣保證了,一個點不超過K次經過,而且第一次經過就將上面的數取走了,再經過就沒有數可取了。

一個點要和自己連得方法是,都加一個比較大的數。比如一共n^2個點,那麽1節點連向1+n^2,就是自己和自己連邊了。

還有個問題開始困擾時間比較長,第一是源點為什麽不能就是1,匯點是n^2.

因為這樣節點有兩條邊連接,每條邊的容量是K,這樣流入節點的容量可以是2*k,那麽就不是不超過k次經過了。而是2*k.

這樣一來畫出來圖就是:

技術分享圖片

然後就是最低費用最大流問題。

一直re,通常情況下是數組的問題。檢查了很久發現,一個點要有4條邊,一條是容量是1,另一條是K-1,還有兩條反向邊。因此,是n^2*4的邊數。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<queue>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
int n,k,ans,hd[6010],cnt=1,a[55][55],flow[6010];
int dis[6010],vis[6010],last[6010];
int s,t,pre[6010];
struct Edge{
    int nxt,to,flw,cos;
}edge[20010
]; void add(int u,int v,int w,int f) { cnt++; edge[cnt].to=v; edge[cnt].flw=w; edge[cnt].cos=f; edge[cnt].nxt =hd[u]; hd[u]=cnt; } queue<int> q; int spfa(int s,int t) { memset(dis,0x3f,sizeof dis); memset(vis,0,sizeof vis); memset(flow,0x3f,sizeof flow); // memset(last,0,sizeof last);
memset(pre,-1,sizeof pre); q.push(s); vis[s]=1; dis[s]=0; pre[t]=-1; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=hd[u];i;i=edge[i].nxt) { int v=edge[i].to; if(edge[i].flw>0 && dis[v]>dis[u]-edge[i].cos) { flow[v]=min(flow[u],edge[i].flw); dis[v]=dis[u]-edge[i].cos; last[v]=i; pre[v]=u; if(!vis[v]) { q.push(v); vis[v]=1; } } } vis[u]=0; } return pre[t]!=-1; } int mxcost=0; void mcmf() { while(spfa(s,t)) { mxcost+=(-dis[t]);// int now=t; while(now!=s) { edge[last[now]].flw-=flow[t]; edge[last[now]^1].flw+=flow[t]; now=pre[now]; } } } int main() { scanf("%d%d",&n,&k); int N=n*n; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { int q,p=n*(i-1)+j; scanf("%d",&a[i][j]); add(p,p+N,1,a[i][j]);//自己連自己 add(p+N,p,0,-a[i][j]);//反向邊 add(p,p+N,k-1,0);//另一條邊,容量為K-1的,費用為0,保證了K的流量 add(p+N,p,0,0); //反向邊 if(i-1>0) { q=n*(i-2)+j+N;//上一行的點的出點 add(q,p,k,0); add(p,q,0,0); //只有出點連邊 } if(j-1>0) { add(p-1+N,p,k,0);//左一行的點的出點 add(p,p-1+N,0,0); } // for(int j=hd[p];j;j=edge[j].nxt) // { // cout<<p<<","<<edge[j].to<<","<<edge[j].flw<<","<<edge[j].cos<<endl; // } } // for(int u=1;u<=2*n*n;u++) // for(int j=hd[u];j;j=edge[j].nxt) // { // cout<<u<<","<<edge[j].to<<","<<edge[j].flw<<","<<edge[j].cos<<endl; // } s=1;t=2*n*n; mcmf(); printf("%d\n",mxcost); }

P2045 方格取數加強版