TopCoder SRM 570 Div1 CurvyonRails

TopCoder SRM 570 Div1 CurvyonRails

题意: 一个\(n\times m\)的网格图,其中有一些点需要建铁路,有一些点为关键点,在关键点上修直铁路会产生1的代价,求最小的代价

由于\(n,m\leq 25\)显然不可以插头\(\text{dp}\)。。。

考虑轨道联通实际上类似网络流的形式

考虑一个常见的思路: 网格图可以简化为二分图 然后 跑网络流

先不考虑代价的问题,判断是否存在合法方案

每个格子要有两条出边,因此可以让\(S\)向左侧点连边权为2的边,右侧点向\(T\)连边权为2的边

然后可以让每个左侧点向相邻的右侧点连边,即考虑了联通关系

下面考虑代价的计算,加入边的代价,即为费用流

连同向边会产生代价,因此考虑为每个节点新增两个节点,表示向上下/左右连边

对于让原节点对于新增的上下和左右节点 分别连两条代价为0和1的边

这样如果流了同向边,就会产生代价

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair <int,int> Pii;
#define pb push_back
#define mp make_pair
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }

char IO;
int rd(){
	int s=0;
	int f=0;
	while(!isdigit(IO=getchar())) if(IO=='-') f=1;
	do s=(s<<1)+(s<<3)+(IO^'0');
	while(isdigit(IO=getchar()));
	return f?-s:s;
}

const int N=25*30*3,M=N<<3,INF=1e9+10;

int n,m,k;
int a[30][30];

// Max Flow Min Cost

int id[30][30][2];
struct Edge{
	int to,nxt,w,c;
}e[M];
int head[N],ecnt,S,T,V;
void Clear(){
	rep(i,1,V) head[i]=0;
	ecnt=1,V=0;
}
void AddEdge(int u,int v,int w,int c) {
	e[++ecnt]=(Edge){v,head[u],w,c};
	head[u]=ecnt;
}
void Link(int u,int v,int w,int c=0){ AddEdge(u,v,w,c),AddEdge(v,u,0,-c); }
#define erep(u,i) for(int i=head[u],v=e[i].to,w=e[i].w,c=e[i].c;i;i=e[i].nxt,v=e[i].to,w=e[i].w,c=e[i].c)

int dis[N];
int SPFA(){
	static int inq[N];
	static queue <int> que;
	rep(i,1,V) dis[i]=INF;
	que.push(S),dis[S]=0;
	while(!que.empty()) {
		int u=que.front(); que.pop();
		inq[u]=0;
		erep(u,i) if(w && dis[v]>dis[u]+c) {
			dis[v]=dis[u]+c;
			if(!inq[v]) inq[v]=1,que.push(v);
		}
	}
	return dis[T]<INF;
}
int Dfs(int u,int in) {
	if(u==T) return in;
	int out=0,t=dis[u]; dis[u]=INF;
	erep(u,i) if(w && dis[v]==t+c) {
		int t=Dfs(v,min(in-out,w));
		e[i].w-=t,e[i^1].w+=t,out+=t;
		if(in==out) break;
	}
	if(out) dis[u]=t;
	return out;
}

Pii Dinic(){
	int flow=0,cost=0;
	while(SPFA()) 
		for(int t;(t=Dfs(S,INF));) flow+=t,cost+=dis[T]*t;
	return mp(flow,cost);
}

class CurvyonRails {
	public:
		int getmin(vector <string> field) {
			n=field.size(),m=field[0].size();
			rep(i,0,n-1) rep(j,0,m-1) a[i+1][j+1]=field[i][j];
			k=0,Clear();
			rep(i,1,n) rep(j,1,m) if(a[i][j]!='w') {
				k++;
				rep(d,0,1) id[i][j][d]=++V;
			}
			S=++V,T=++V;
			rep(i,1,n) rep(j,1,m) if(a[i][j]!='w') {
				if((i+j)&1){
					Link(S,++V,2,0);
					rep(d,0,1) {
						Link(V,id[i][j][d],1,0);
						Link(V,id[i][j][d],1,a[i][j]=='C');
						// 如果两条走了同向,就会产生1的代价
					}
					if(i<n && a[i+1][j]!='w') Link(id[i][j][0],id[i+1][j][0],1,0);
					if(j<m && a[i][j+1]!='w') Link(id[i][j][1],id[i][j+1][1],1,0);
				} else {
					Link(++V,T,2,0);
					rep(d,0,1) {
						Link(id[i][j][d],V,1,0);
						Link(id[i][j][d],V,1,a[i][j]=='C');
						// 如果两条走了同向,就会产生1的代价
					}
					if(i<n && a[i+1][j]!='w') Link(id[i+1][j][0],id[i][j][0],1,0);
					if(j<m && a[i][j+1]!='w') Link(id[i][j+1][1],id[i][j][1],1,0);
				}
			}
			Pii ans=Dinic();
			if(ans.first!=k) return -1;
			return ans.second;
		}
};
//Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!

上一篇:学BFS前熟练掌握的队列知识


下一篇:C++ 同步通信