【CQOI 2006】移动棋子

Description

   在一个n*n的棋盘上有n枚棋子。每次可以把一枚棋子往上、下、左、右方向之一移动一格,最后排成一行、一列或者主、副对角线上(因此一共有2n+2条可能的目标状态),要求移动次数最小。 
   棋盘上有一些位置是障碍,棋子在任何时候都不能经过。棋子的初始位置保证不在障碍物上。任两枚棋子不能在同时到达 同一个格子。 

Input

第一行包含两个整数n, m,表示棋子的个数(它也是棋盘的边长)和障碍的个数。以下n行,每行两个整数(x, y),表示第i个棋子的坐标(1<=x, y<=n),以下m行,每行给出一个障碍物的坐标。假设这n+m个坐标两两不重合。

Output

一个整数,表示最小移动步数。如果无解,输出-1。

Sample Input

5 1
1 2
2 4
3 4
5 1
5 3
1 1

Sample Output

6

Hint

50%的数据满足:2<=n<=15,m=0 
100%的数据满足:2<=n<=50, 0<=m<=100


【分析】

枚举+费用流

每次枚举一行或一列或一条对角线,判断这一行、列、对角线有没有障碍,如果没有,那么建图:
(1)源点→棋子初始位置,流量1,费用0;
(2)棋子的初始位置→任意一个目标位置,流量1,费用为移动的步数(可以预处理出来);
(3)目标位置→汇点,流量1费用0。
然后费用流跑一下,记下费用最小的一次就可以了。
不需要什么优化,除了费用流以外,此题纯属考察代码能力。
每次费用流O(N^3),加上枚举了2N+2次,总的复杂度O(N^4),一秒钟就够了但是这道题有5秒钟。


【代码】

/***************************
    ID:Ciocio
	LANG:C++
	DATE:2013-12-22
	TAKS:CQOI 2006 Move
***************************/
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define MAXR 55
#define MAXN 5005
#define INF 999999999
#define loc(x,y) ((x-1)*N+y)
#define MAXM 50000

int N,M,Sta,End,Maxflow,Mincost,ans=INF;
int mat[MAXR][MAXR],step[MAXR][MAXN];
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
bool vis[MAXR][MAXR],row[MAXR],cow[MAXR],ma,mt;
int Dis[MAXN],path[MAXN],mark[MAXN],chose[MAXN];
struct wjj{int x,y;}A[MAXR];
int Y[MAXM],W[MAXM],C[MAXM],Next[MAXM],Last[MAXN];

int totE=1;
void _addedge(int u,int v,int w,int c)
{
	Y[++totE]=v;W[totE]=w;C[totE]=c;
	Next[totE]=Last[u];
	Last[u]=totE;
	Y[++totE]=u;W[totE]=0;C[totE]=-c;
	Next[totE]=Last[v];
	Last[v]=totE;
}

void _init()
{
	scanf("%d%d",&N,&M);
	int x,y;
	for(int i=1;i<=N;i++)
	{
		scanf("%d%d",&x,&y);
		mat[x][y]=1;
		A[i].x=x;
		A[i].y=y;
	}
	for(int i=1;i<=M;i++)
	{
		scanf("%d%d",&x,&y);
		mat[x][y]=-1;
		row[y]=true;
		cow[x]=true;
		if(x==y) ma=true;
		if(x+y==N+1) mt=true;
	}
}

struct node{
	int x,y;
	node(int _x,int _y):x(_x),y(_y){}
};
queue  BQ;
void _Bfs(int u)
{
	memset(vis,0,sizeof(vis));
	while(!BQ.empty()) BQ.pop();
	int i=A[u].x,j=A[u].y;
	BQ.push(node(i,j));
	vis[i][j]=true;
	while(!BQ.empty())
	{
		node p=BQ.front();BQ.pop();
		int x=p.x,y=p.y;
		for(int k=0;k<=3;k++)
		{
			int tx=x+dir[k][0],ty=y+dir[k][1];
			if(1<=tx&&tx<=N&&1<=ty&&ty<=N&&mat[tx][ty]!=-1&&vis[tx][ty]==false)
			{
				step[u][loc(tx,ty)]=step[u][loc(x,y)]+1;
				vis[tx][ty]=true;
				BQ.push(node(tx,ty));
			}
		}
	}
}

void _addflow()
{
	int flow,i,cost;
	cost=0;flow=INF;
	i=End;
	while((i!=0)&&(path[i]!=-1))
	{
		flow=min(flow,W[chose[i]]);
		cost+=C[chose[i]];
		i=path[i];
	}
	Maxflow+=flow;
	Mincost+=flow*cost;
	i=End;
	while((i!=0)&&(path[i]!=-1))
	{
		W[chose[i]]-=flow;
		W[chose[i]^1]+=flow;
		i=path[i];
	}
}

queue  Q;
bool _findpath()
{
	for(int i=Sta;i<=End;i++) {Dis[i]=INF;path[i]=-1;mark[i]=false;}
	while(!Q.empty()) Q.pop();
	Dis[Sta]=0;path[Sta]=-1;mark[Sta]=true;Q.push(Sta);
	while(!Q.empty())
	{
		int u=Q.front();Q.pop();
		mark[u]=false;
		for(int j=Last[u];j;j=Next[j])
		{
			int v=Y[j];
			if(W[j]>0&&Dis[v]>Dis[u]+C[j])
			{
				Dis[v]=Dis[u]+C[j];
				path[v]=u;
				chose[v]=j;
				if(!mark[v])
				{
					mark[v]=true;
					Q.push(v);
				}
			}
		}
	}
	return Dis[End]


你可能感兴趣的:(算法题解--图论:网络流)