题目地址:HDU 3468
这道题的关键在于能想到用网络流。然后还要想到用bfs来标记最短路中的点。
首先标记方法是,对每一个集合点跑一次bfs,记录所有点到该点的最短距离。然后对于任意一对起始点来说,只要这个点到起点的最短距离+该点到终点的最短距离==起点到终点的最短距离,就说明这点在某条从起点到终点的最短路上。
然后以集合点建X集,宝物点建Y集构造二分图,将从某集合点出发的最短路中经过宝物点与该集合点连边。剩下的用二分匹配算法或最大流算法都可以。(为什么我的最大流比二分匹配跑的还要快。。。。。。。)。
题目有一点需要注意,就是当从集合点i到i+1没有路的时候,要输出-1.
代码如下:
#include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <map> #include<algorithm> using namespace std; const int INF=0x3f3f3f3f; int head[12001], source, sink, nv, cnt; int cur[12001], num[12001], pre[12001], d[12001]; int d1[60][12001], dd[60], vis[101][101], n, m, goad[12000], id[110][110], tot; int jx[]= {0,0,1,-1}; int jy[]= {1,-1,0,0}; char mp[110][110]; struct node { int u, v, cap, next; } edge[10000000]; void add(int u, int v, int cap) { edge[cnt].v=v; edge[cnt].cap=cap; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].cap=0; edge[cnt].next=head[v]; head[v]=cnt++; } void bfs() { memset(d,-1,sizeof(d)); memset(num,0,sizeof(num)); queue<int>q; q.push(sink); d[sink]=0; num[0]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(d[v]==-1) { d[v]=d[u]+1; num[d[v]]++; q.push(v); } } } } void isap() { memcpy(cur,head,sizeof(cur)); bfs(); int flow=0, u=pre[source]=source, i; while(d[source]<nv) { if(u==sink) { int f=INF, pos; for(i=source;i!=sink;i=edge[cur[i]].v) { if(f>edge[cur[i]].cap) { f=edge[cur[i]].cap; pos=i; } } for(i=source;i!=sink;i=edge[cur[i]].v) { edge[cur[i]].cap-=f; edge[cur[i]^1].cap+=f; } flow+=f; u=pos; } for(i=cur[u];i!=-1;i=edge[i].next) { if(d[edge[i].v]+1==d[u]&&edge[i].cap) break; } if(i!=-1) { cur[u]=i; pre[edge[i].v]=u; u=edge[i].v; } else { if(--num[d[u]]==0) break; int mind=nv; for(i=head[u];i!=-1;i=edge[i].next) { if(mind>d[edge[i].v]&&edge[i].cap) { mind=d[edge[i].v]; cur[u]=i; } } d[u]=mind+1; num[d[u]]++; u=pre[u]; } } printf("%d\n",flow); } int getid(char c) { if(c>='A'&&c<='Z') return c-'A'+1; else if(c>='a'&&c<='z') return c-'a'+27; else return 0; } void bfs(int x, int y) { int i; queue<int>q; q.push(x*m+y); memset(vis,0,sizeof(vis)); vis[x][y]=1; d1[id[x][y]][x*m+y]=0; while(!q.empty()) { int u=q.front(); q.pop(); int a=u/m; int b=u%m; for(i=0; i<4; i++) { int c=a+jx[i]; int d=b+jy[i]; if(c>=0&&c<n&&d>=0&&d<m&&!vis[c][d]&&mp[c][d]!='#') { vis[c][d]=1; d1[id[x][y]][c*m+d]=d1[id[x][y]][a*m+b]+1; q.push(c*m+d); if(id[c][d]==id[x][y]+1) { dd[id[x][y]]=d1[id[x][y]][c*m+d]; } } } } } int main() { int i, j, nu; while(scanf("%d%d",&n,&m)!=EOF) { memset(head,-1,sizeof(head)); memset(d1,INF,sizeof(d1)); memset(dd,INF,sizeof(dd)); cnt=0; nu=0; tot=0; for(i=0; i<n; i++) { scanf("%s",mp[i]); for(j=0; j<m; j++) { if(mp[i][j]=='*') { goad[nu++]=i*m+j; } id[i][j]=getid(mp[i][j]); if(id[i][j]) tot++; } } for(i=0; i<n; i++) { for(j=0; j<m; j++) { if(id[i][j]) { bfs(i,j); } } } for(i=1; i<tot; i++) { if(dd[i]==INF) { printf("-1\n"); break; } } if(i<tot) continue ; source=0; sink=tot+nu+1; nv=sink+1; for(i=1;i<tot;i++) { add(source,i,1); } for(i=1;i<=nu;i++) { add(i+tot,sink,1); } for(i=1; i<tot; i++) { for(j=0; j<nu; j++) { if(d1[i][goad[j]]+d1[i+1][goad[j]]==dd[i]) { add(i,j+tot+1,1); } } } isap(); } return 0; }