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]