【POJ】【P3422】【Kaka's Matrix Travels】【题解】

传送门:http://poj.org/problem?id=3422

传说中的K取方格数,写dp一取方格数的时候就想过K取方格数,一年了啊啊啊

Code:

/*
	ID:zky
	OJ:POJ
	Index:3422
	Language:C++
*/
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
#define pb push_back 
using namespace std;
const int INF=INT_MAX;
int n,mm,m,k;
int map[51][51];
struct edge{
	int u,v,cap,flow,cost;
	edge(int _u,int _v,int _cap,int _flow,int _cost){
		u=_u;
		v=_v;
		cap=_cap;
		flow=_flow;
		cost=_cost;
	}
};
vector<edge>edges;
vector<vector<int> >G;
void add(int u,int v,int cap,int cost){
	edges.pb(edge(u,v,cap,0,cost));
	mm=edges.size();
	G[u].pb(mm-1);
}
int hash[51][51];
int tot=0;
int s,t;
int d[5110];
int vis[5110];
int a[5100];
int prev[5100];
int flow=0,cost=0;
bool spfa(){
	queue<int>q;
	q.push(s);
	memset(d,0xaf,sizeof(d));
	memset(vis,0,sizeof(vis));
	int B=d[0];
	d[s]=0;
	vis[s]=1;
	a[s]=INF;
	while(!q.empty()){
		int u=q.front();q.pop();vis[u]=0;
		for(int i=0;i<G[u].size();i++){
			edge &e=edges[G[u][i]];
			if(e.cap-e.flow>0&&d[e.v]<d[u]+e.cost){
				d[e.v]=d[u]+e.cost;
				prev[e.v]=G[u][i];
				a[e.v]=min(a[u],e.cap-e.flow);
				if(!vis[e.v]){
					vis[e.v]=1;
					q.push(e.v);
				}
			}
		}
//		vis[u]=0;
	}
	if(d[t]==B)return false;
	int u=t;
	flow+=a[t];
	cost+=a[t]*d[t];
	while(u!=s){
		edges[prev[u]].flow+=a[t];
		edges[prev[u]^1].flow-=a[t];
		u=edges[prev[u]].u;
	}
	return true;
}
void zky(){
	flow=0;cost=0;
	while(spfa());
	cout<<cost<<endl;
}
int main(){
	while(cin>>n>>k){
	G.resize(n*n*2+2);
	G.clear();tot=0;edges.clear();
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++)
	cin>>map[i][j];
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++){
		hash[i][j]=++tot;
	}
	for(int i=1;i<=n;i++)
	for(int j=1;j<=n;j++){
		int u=hash[i][j],v=hash[i][j]+tot;
		add(u,v,1,map[i][j]);
		add(v,u,1,-map[i][j]);
		
		add(u,v,k,0);
		add(v,u,0,0);
		
		u=v;
		if(i+1<=n){
			v=hash[i+1][j];
			add(u,v,k,0);
			add(v,u,0,0);
		}
		if(j+1<=n){
			v=hash[i][j+1];
			add(u,v,k,0);
			add(v,u,0,0);
		}
	}
	s=0;t=tot*2+1;
	add(s,hash[1][1],k,0);
	add(hash[1][1],s,0,0);
	add(hash[n][n]+tot,t,k,0);
	add(t,hash[n][n]+tot,0,0);
	int debugG=0;
	if(debugG){
		for(int i=0;i<edges.size();i++){
			printf("#%d   %d -> %d  cap:%d cost:%d\n",i,edges[i].u,edges[i].v,edges[i].cap,edges[i].cost);
		}
	}
	zky();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值