标签:treasure hunting hdu 3468 二分匹配+bfs最短路径
2 4 A.B. ***C 2 4 A#B. ***C
1 2
题意:在一个R*C的地图内,字母表示集合点,‘*’表示宝藏,‘.’表示空地,现在沿着A->....->Z->a->....->z的方向走,途中从一个集合点到下一个集合点之间只能捡一个宝藏,问最后最多能捡多少宝藏。
思路:将集合点和宝藏分别看成两个集合,若在集合点x到y的最短路径上有‘*’,那么就在x和‘*’之间连边。bfs求出所有集合点到下一个集合点的最短路径。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 1005
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b) for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b) for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v) memset ((t) , v, sizeof(t))
#define sf(n) scanf("%d", &n)
#define sff(a,b) scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf printf
#define DBG pf("Hi\n")
typedef long long ll;
using namespace std;
struct Node
{
int x,y;
int step;
};
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int g[60][10005];
int linker[10005];
char mp[105][105];
int id1[105][105],id2[105][105];
int dist1[60][10005],dist2[60][60];
int R,C,uN,vN;
bool used[10005];
bool vis[105][105];
bool dfs(int u)
{
for (int v=1;v<=vN;v++)
{
if (g[u][v]&&!used[v])
{
used[v]=true;
if (linker[v]==-1||dfs(linker[v]))
{
linker[v]=u;
return true;
}
}
}
return false;
}
int hungary()
{
int res=0;
memset(linker,-1,sizeof(linker));
for (int u=1;u<=uN;u++)
{
memset(used,false,sizeof(used));
if (dfs(u)) res++;
}
return res;
}
bool isok(Node a)
{
if (a.x>=0&&a.x<R&&a.y>=0&&a.y<C) return true;
return false;
}
void bfs(int sx,int sy)
{
int minn=INF;
queue<Node>Q;
Node st,now;
while (!Q.empty()) Q.pop();
st.x=sx;st.y=sy;
st.step=0;
memset(vis,false,sizeof(vis));
vis[sx][sy]=true;
Q.push(st);
// printf("%d %d+\n",sx,sy);
while (!Q.empty())
{
st=Q.front(); Q.pop();
for (int i=0;i<4;i++)
{
now.x=st.x+dir[i][0];
now.y=st.y+dir[i][1];
now.step=st.step+1;
if (isok(now)&&mp[now.x][now.y]!='#'&&!vis[now.x][now.y])
{
// printf("%d %d\n",now.x,now.y);
vis[now.x][now.y]=true;
Q.push(now);
if (mp[now.x][now.y]=='*')
dist1[id1[sx][sy]][id2[now.x][now.y]]=now.step;
if (id1[now.x][now.y]==id1[sx][sy]+1)
dist2[id1[sx][sy]][id1[now.x][now.y]]=now.step;
}
}
}
}
int main()
{
// freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin);
int i,j;
while (~scanf("%d%d",&R,&C))
{
int cnt1=0,cnt2=1;
int have[60];
memset(have,0,sizeof(have));
memset(id1,0,sizeof(id1));
memset(g,0,sizeof(g));
memset(id2,0,sizeof(id2));
for (i=0;i<R;i++)
{
scanf("%s",mp[i]);
for (j=0;j<C;j++)
{
if (mp[i][j]>='A'&&mp[i][j]<='Z')
{
id1[i][j]=mp[i][j]-'A'+1; //给集合点标号
cnt1++;
have[id1[i][j]]=1;
}
else if (mp[i][j]>='a'&&mp[i][j]<='z')
{
id1[i][j]=mp[i][j]-'a'+27; //给集合点标号
cnt1++;
have[id1[i][j]]=1;
}
else if (mp[i][j]=='*')
id2[i][j]=cnt2++; //给宝藏标号
}
}
for (i=1;i<=cnt1;i++) //若集合点中间断层了直接输出-1
if (!have[i]) break;
if (i<=cnt1){
printf("-1\n");
continue;
}
for (i=0;i<cnt1+10;i++)
for (j=0;j<cnt1+10;j++)
dist2[i][j]=-1; //dist2[i][[j]表示集合点i到集合点j的最短距离
for (i=0;i<cnt1+10;i++)
for (j=0;j<cnt2+10;j++)
dist1[i][j]=-1; //dist1[i][j]表示集合点i到宝藏j的最短距离
int flag=1;
for (i=0;i<R;i++)
{
for (j=0;j<C;j++)
{
if (id1[i][j])
bfs(i,j);
}
}
for (i=1;i<cnt1;i++) //若有两个集合点之间不可到达直接输出-1
if (dist2[i][i+1]==-1){
flag=0;
break;
}
if (!flag)
{
// DBG;
printf("-1\n");
continue;
}
// DBG;
for (i=0;i<R;i++)//建图
{
for (j=0;j<C;j++)
{
if (id1[i][j])
{
for (int k=1;k<cnt2;k++)
{
if (dist1[id1[i][j]][k]+dist1[id1[i][j]+1][k]==dist2[id1[i][j]][id1[i][j]+1])
g[id1[i][j]][k]=1;
}
}
}
}
uN=cnt1;vN=cnt2-1;
printf("%d\n",hungary());
}
return 0;
}
Treasure Hunting (hdu 3468 二分匹配+bfs最短路径)
标签:treasure hunting hdu 3468 二分匹配+bfs最短路径
原文地址:http://blog.csdn.net/u014422052/article/details/45421661