标签: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