Treasure Hunting
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 1605 Accepted Submission(s): 421
Total Submission(s): 1605 Accepted Submission(s): 421
Problem Description
Do you like treasure hunting? Today, with one of his friend, iSea is on a venture trip again. As most movie said, they find so many gold hiding in their trip.
Now iSea’s clever friend has already got the map of the place they are going to hunt, simplify the map, there are three ground types:
● '.' means blank ground, they can get through it
● '#' means block, they can’t get through it
● '*' means gold hiding under ground, also they can just get through it (but you won’t, right?)
What makes iSea very delighted is the friend with him is extraordinary justice, he would not take away things which doesn’t belong to him, so all the treasure belong to iSea oneself!
But his friend has a request, he will set up a number of rally points on the map, namely 'A', 'B' ... 'Z', 'a', 'b' ... 'z' (in that order, but may be less than 52), they start in 'A', each time friend reaches to the next rally point in the shortest way, they have to meet here (i.e. iSea reaches there earlier than or same as his friend), then start together, but you can choose different paths. Initially, iSea’s speed is the same with his friend, but to grab treasures, he save one time unit among each part of road, he use the only one unit to get a treasure, after being picked, the treasure’s point change into blank ground.
Under the premise of his friend’s rule, how much treasure iSea can get at most?
Now iSea’s clever friend has already got the map of the place they are going to hunt, simplify the map, there are three ground types:
● '.' means blank ground, they can get through it
● '#' means block, they can’t get through it
● '*' means gold hiding under ground, also they can just get through it (but you won’t, right?)
What makes iSea very delighted is the friend with him is extraordinary justice, he would not take away things which doesn’t belong to him, so all the treasure belong to iSea oneself!
But his friend has a request, he will set up a number of rally points on the map, namely 'A', 'B' ... 'Z', 'a', 'b' ... 'z' (in that order, but may be less than 52), they start in 'A', each time friend reaches to the next rally point in the shortest way, they have to meet here (i.e. iSea reaches there earlier than or same as his friend), then start together, but you can choose different paths. Initially, iSea’s speed is the same with his friend, but to grab treasures, he save one time unit among each part of road, he use the only one unit to get a treasure, after being picked, the treasure’s point change into blank ground.
Under the premise of his friend’s rule, how much treasure iSea can get at most?
Input
There are several test cases in the input.
Each test case begin with two integers R, C (2 ≤ R, C ≤ 100), indicating the row number and the column number.
Then R strings follow, each string has C characters (must be ‘A’ – ‘Z’ or ‘a’ – ‘z’ or ‘.’ or ‘#’ or ‘*’), indicating the type in the coordinate.
The input terminates by end of file marker.
Each test case begin with two integers R, C (2 ≤ R, C ≤ 100), indicating the row number and the column number.
Then R strings follow, each string has C characters (must be ‘A’ – ‘Z’ or ‘a’ – ‘z’ or ‘.’ or ‘#’ or ‘*’), indicating the type in the coordinate.
The input terminates by end of file marker.
Output
For each test case, output one integer, indicating maximum gold number iSea can get, if they can’t meet at one or more rally points, just output -1.
Sample Input
2 4 A.B. ***C 2 4 A#B. ***C
Sample Output
1 2
题意:在地图上从A -> B -> C …… -> Z -> a -> b …… -> z 这样走,每次走的都是最短路(可能多条路径),地图上有一些金子,如果在某一条最短路上存在金子,那么只取一个金子。问最多能取多少金子。
分析:先bfs预处理出每个点(A.B.C……)到其他点的最短路径,然后对于每个金子,判断其是否在某条最短路径上,假设gold1在(A -> B)的最短路径上,那么A连向gold1,依次类推,就建立了二分图模型了,然后求二分图最大匹配即可。若用网络流,那么所有的边容量设为1;加入超级源点s,连向所有的点(A.B.C……),容量为1;加入超级汇点t,所有的金子连向t,容量为1。然后跑一遍最大流。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3468
代码清单:
二分图匹配
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<cctype>
#include<string>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define end() return 0
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxN = 100 + 5;
const int maxn = 10000 + 5;
const int maxv = 100000 + 5;
const int INF = 0x7f7f7f7f;
struct Node{
int x,y;
Node(){}
Node(int _x,int _y):x(_x),y(_y){}
}rally[60];
int C,R;
char str[maxN][maxN];
int dist[60][10005];
int gold[10005],go;
bool vis[maxN][maxN];
int ra,tail;
vector<int>graph[60];
int match[maxn];
bool vist[maxn];
void init(){
ra=-1; go=0;
memset(dist,INF,sizeof(dist));
memset(match,-1,sizeof(match));
for(int i=0;i<60;i++) graph[i].clear();
}
int get_rally(char s){
if(s>='A'&&s<='Z') return s-'A'+1;
if(s>='a'&&s<='z') return s-'a'+27;
return 0;
}
void input(){
for(int i=0;i<C;i++){
scanf("%s",str[i]);
for(int j=0;j<R;j++){
if(str[i][j]=='*') gold[go++]=i*R+j;
else{
int idx=get_rally(str[i][j]);
if(idx){ rally[idx]=Node(i,j); ra=max(ra,idx);}
}
}
}
}
int X[]={0,-1,0,1};
int Y[]={-1,0,1,0};
void bfs(int idx,Node s){
memset(vis,false,sizeof(vis));
queue<Node>q;
while(!q.empty()) q.pop();
q.push(s);
vis[s.x][s.y]=true;
dist[idx][s.x*R+s.y]=0;
while(!q.empty()){
Node p=q.front();q.pop();
for(int i=0;i<4;i++){
int xx=p.x+X[i];
int yy=p.y+Y[i];
if(xx>=0&&xx<C&&yy>=0&&yy<R&&!vis[xx][yy]&&str[xx][yy]!='#'){
vis[xx][yy]=true;
q.push(Node(xx,yy));
dist[idx][xx*R+yy]=dist[idx][p.x*R+p.y]+1;
}
}
}
}
void createGraph(){
for(int i=1;i<ra;i++){
int idx=rally[i+1].x*R+rally[i+1].y;
for(int j=0;j<go;j++){
if(dist[i][gold[j]]+dist[i+1][gold[j]]==dist[i][idx])
graph[i].push_back(ra+j+1);
}
}
}
bool dfs(int u){
for(int i=0;i<graph[u].size();i++){
int v=graph[u][i];
if(!vist[v]){
vist[v]=true;
if(match[v]==-1 || dfs(match[v])){
match[v]=u;
return true;
}
}
}return false;
}
void solve(){
for(int i=1;i<=ra;i++){
bfs(i,rally[i]);
}
if(ra==1) {
printf("-1\n");
return ;
}
for(int i=1;i<ra;i++){
int idx=rally[i+1].x*R+rally[i+1].y;
if(dist[i][idx]==INF){
printf("-1\n");
return ;
}
}
createGraph();
int ans=0;
for(int i=1;i<ra;i++){
memset(vist,false,sizeof(vist));
if(dfs(i)) ans++;
}
printf("%d\n",ans);
}
int main(){
while(scanf("%d%d",&C,&R)!=EOF){
init();
input();
solve();
}end();
}
最大流dinic
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<cctype>
#include<string>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define end() return 0
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxN = 100 + 5;
const int maxn = 10000 + 5;
const int maxv = 100000 + 5;
const int INF = 0x7f7f7f7f;
struct Edge{
int from,to,cap,flow;
Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){}
};
struct dinic{
int n,m,s,t; //结点数,边数(包括反向弧),源点,汇点
vector<Edge>edge;//边表。edge[e]和edge[e^1]互为反向弧
vector<int>G[maxn];//邻接表。G[i][j]表示结点i的第j条边在e数组的序号
bool vis[maxn]; //bfs用
int d[maxn]; //从起点到i的距离
int cur[maxn]; //当前弧下标
void init(int n,int s,int t){
this -> n = n;
this -> s = s;
this -> t = t;
for(int i=0;i<=n;i++) G[i].clear();
edge.clear();
}
void addEdge(int from,int to,int cap){
edge.push_back(Edge(from,to,cap,0));
edge.push_back(Edge(to,from,0,0));
m=edge.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool bfs(){
memset(vis,false,sizeof(vis));
queue<int>q;
q.push(s);
d[s]=0;
vis[s]=true;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<G[x].size();i++){
Edge& e=edge[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow){ //只考虑残量网络中的弧
vis[e.to]=true;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return vis[t];
}
int dfs(int x,int a){
if(x==t||a==0) return a;
int flow=0,f;
for(int& i=cur[x];i<G[x].size();i++){ // & -> 从上次考虑的弧
Edge& e=edge[G[x][i]];
if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edge[G[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int maxflow(){
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
};
struct Node{
int x,y;
Node(){}
Node(int _x,int _y):x(_x),y(_y){}
}rally[60];
int C,R;
char str[maxN][maxN];
int dist[60][10005];
int gold[10005],go;
bool vis[maxN][maxN];
int ra,tail;
dinic dc;
void init(){
ra=-1; go=0;
memset(dist,INF,sizeof(dist));
}
int get_rally(char s){
if(s>='A'&&s<='Z') return s-'A'+1;
if(s>='a'&&s<='z') return s-'a'+27;
return 0;
}
void input(){
for(int i=0;i<C;i++){
scanf("%s",str[i]);
for(int j=0;j<R;j++){
if(str[i][j]=='*') gold[go++]=i*R+j;
else{
int idx=get_rally(str[i][j]);
if(idx){ rally[idx]=Node(i,j); ra=max(ra,idx);}
}
}
}
}
int X[]={0,-1,0,1};
int Y[]={-1,0,1,0};
void bfs(int idx,Node s){
memset(vis,false,sizeof(vis));
queue<Node>q;
while(!q.empty()) q.pop();
q.push(s);
vis[s.x][s.y]=true;
dist[idx][s.x*R+s.y]=0;
while(!q.empty()){
Node p=q.front();q.pop();
for(int i=0;i<4;i++){
int xx=p.x+X[i];
int yy=p.y+Y[i];
if(xx>=0&&xx<C&&yy>=0&&yy<R&&!vis[xx][yy]&&str[xx][yy]!='#'){
vis[xx][yy]=true;
q.push(Node(xx,yy));
dist[idx][xx*R+yy]=dist[idx][p.x*R+p.y]+1;
}
}
}
}
void createGraph(){
tail=ra+go+1;
dc.init(tail+1,0,tail);
for(int i=1;i<ra;i++){
dc.addEdge(0,i,1);
int idx=rally[i+1].x*R+rally[i+1].y;
for(int j=0;j<go;j++){
if(dist[i][gold[j]]+dist[i+1][gold[j]]==dist[i][idx])
dc.addEdge(i,ra+j+1,1);
}
}
for(int j=0;j<go;j++){
dc.addEdge(j+ra+1,tail,1);
}
}
void solve(){
for(int i=1;i<=ra;i++){
bfs(i,rally[i]);
}
if(ra==1) {
printf("-1\n");
return ;
}
for(int i=1;i<ra;i++){
int idx=rally[i+1].x*R+rally[i+1].y;
if(dist[i][idx]==INF){
printf("-1\n");
return ;
}
}
createGraph();
printf("%d\n",dc.maxflow());
}
int main(){
while(scanf("%d%d",&C,&R)!=EOF){
init();
input();
solve();
}end();
}