HDU 3468-Treasure Hunting 网络流or二分匹配

86 篇文章 0 订阅
5 篇文章 0 订阅

Treasure Hunting

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 2208    Accepted Submission(s): 604


 

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?
 

 

 

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.

 

 

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

 

题意:

      简化一下题意吧。n*m的地图,上面有#(不能走),.(可以走),*(宝藏)和字母。有两个人小A和小B,两人都会从地图A出发,小A会从A开始按顺序走到B,C...Z,a,b..z,一直走到最后一个单词为止,即如果只有ABC就走到C,如果只有ABD那么就不合法,每次都走最短路。小B也会按小A的速度走最短路(即同时到达下一个点),但是他可以走不同的路线,如果路线上有宝藏,他就会挖宝藏,但是从一个字母走到另一个字母的过程中他只能挖一个宝藏。

      如果过程不合法请输出-1,如果合法,请输出小B最多可以获得多少个宝藏。

 

做法:

    首先处理最短路的问题,可以因为地图不是很大只有100*100,所以可以枚举每个字母作为起点进行bfs,处理出每个字母到图上任一点的最短路径,然后再枚举每一对起点和终点(即A和B,B和C),看看他们两个到每个宝藏的路径之和是否等于他们彼此相互到达的距离,如果是,那么这个宝藏就是在最短路上的,否则就不是。

    对于在最短路上的宝藏,这里有两种做法。

    1.最大流:将超级原点和每一个字母都增加1的流量,再把每个字母出发能到的宝藏的流量也设为1,每个宝藏都与超级汇点相连接,流量设为1,因为有超级远点到字母流量只有1的限制,所以每个字母只能对应着一个宝藏进入超级汇点,这样跑出来的最大流就是我们想要的答案。

     2.二分匹配:在判断出该字母出发可以到达该宝藏之后,就给字母到该宝藏增加一条单向边,然后跑一边二分匹配即可,因为这样每个字母只能对应一个宝藏,匹配出来的肯定是最优的。


网络流代码如下:

  

#include<bits/stdc++.h>
using namespace std;
const int Ni = 2000005;
const int inf=0x3f3f3f3f;
const int MAX = 1<<26;
struct Edge{
    int u,v,c;
    int next;
}edge[3*Ni];
int n,m;
int edn;//边数
int p[Ni];//父亲
int d[Ni];
int sp,tp;//原点,汇点
char mp[105][105];
int afterdeal[105][105];
void addedge(int u,int v,int c){
    edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;
    edge[edn].next=p[u]; p[u]=edn++;

    edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;
    edge[edn].next=p[v]; p[v]=edn++;
}
int bfs(){
    queue <int> q;
    memset(d,-1,sizeof(d));
    d[sp]=0;
    q.push(sp);
    while(!q.empty()){
        int cur=q.front();
        q.pop();
        for(int i=p[cur];i!=-1;i=edge[i].next){
            int u=edge[i].v;
            if(d[u]==-1 && edge[i].c>0){
                d[u]=d[cur]+1;
                q.push(u);
            }
        }
    }
    return d[tp] != -1;
}
int dfs(int a,int b){
    int r=0;
    if(a==tp)return b;
    for(int i=p[a];i!=-1 && r<b;i=edge[i].next)
    {
        int u=edge[i].v;
        if(edge[i].c>0 && d[u]==d[a]+1)
        {
            int x=min(edge[i].c,b-r);
            x=dfs(u,x);
            r+=x;
            edge[i].c-=x;
            edge[i^1].c+=x;
        }
    }
    if(!r)d[a]=-2;
    return r;
}

int dinic(int sp,int tp){
    int total=0,t;
    while(bfs()){
        while(t=dfs(sp,MAX))
        total+=t;
    }
    return total;
}
int gainpo(int x,int y){
    return (x-1)*m+y;
}
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct node{
    int x,y,step;
    node(){}
    node(int x,int y,int step):x(x),y(y),step(step){}
    bool operator < (const node &a) const {
        return step>a.step;
    }
};
struct Rest{
    int x,y;
}rest[60];
struct Tsure{
    int x,y;
}treasure[10010];
int dis[60][10010],whe[60],mmax,vis[105][105];
void init(){
    memset(whe,0,sizeof(whe));
    edn=0;
    memset(p,-1,sizeof(p));
}
void bfss(int sx,int sy,int now){
    priority_queue<node> q;
    q.push(node(sx,sy,0));
    memset(vis,0,sizeof(vis));
    vis[sx][sy]=1;
    for(int i=0;i<10010;i++){
        dis[now][i]=inf;
    }
    while(!q.empty()){
        node a=q.top(); q.pop();
        dis[now][gainpo(a.x,a.y)]=a.step;
        for(int i=0;i<4;i++){
            int dx=a.x+dir[i][0],dy=a.y+dir[i][1];
            if(dx<=0||dy<=0||dx>n||dy>m||vis[dx][dy]||mp[dx][dy]=='#') continue;
            vis[dx][dy]=1;q.push(node(dx,dy,a.step+1));
        }
    }
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        init();
        sp=0,tp=10500;
        int numtre=0;
        mmax=-1;
        for(int i=1;i<=n;i++)
            scanf("%s",mp[i]+1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(mp[i][j]=='*'){
                    treasure[numtre].x=i,treasure[numtre++].y=j;
                    addedge(gainpo(i,j)+100,tp,1);
                }
                else if(mp[i][j]>='A'&&mp[i][j]<='Z'){
                    int th=mp[i][j]-'A'+1;
                    if(th>mmax) mmax=th;
                    whe[th]=1,rest[th].x=i,rest[th].y=j;
                }
                else if(mp[i][j]>='a'&&mp[i][j]<='z'){
                    int th=mp[i][j]-'a'+27;
                    if(th>mmax) mmax=th;
                    whe[th]=1,rest[th].x=i,rest[th].y=j;
                }
            }
        }
        int flag=0,nowid=1;
        for(int i=1;i<=mmax;i++){
            if(!whe[i]){
                flag=1;break;
            }
            bfss(rest[i].x,rest[i].y,i);
        }
        if(flag) {
            cout<<"-1"<<endl;
            continue;
        }
        for(int i=1;i<mmax;i++){
            int alldis=dis[i][gainpo(rest[i+1].x,rest[i+1].y)];
            if(alldis==inf){
                flag=1; break;
            }
            for(int j=0;j<numtre;j++){
                int dis1=dis[i][gainpo(treasure[j].x,treasure[j].y)];
                int dis2=dis[i+1][gainpo(treasure[j].x,treasure[j].y)];
                if(dis1+dis2==alldis) addedge(i,gainpo(treasure[j].x,treasure[j].y)+100,1);
            }
        }
        if(flag){
            cout<<"-1"<<endl;
            continue;
        }
        for(int i=1;i<60;i++)
            addedge(0,i,1);
        int ans=dinic(sp,tp);
        printf("%d\n",ans);
    }
    return 0;
}

 

 

二分匹配代码如下:

   

#include<bits/stdc++.h>
using namespace std;
const int Ni = 2000005;
const int inf=0x3f3f3f3f;
const int MAX = 1<<26;
struct Edge{
    int u,v;
    int next;
}edge[3*Ni];
int n,m;
int edn;//边数
int p[Ni];
char mp[105][105];
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
struct node{
    int x,y,step;
    node(){}
    node(int x,int y,int step):x(x),y(y),step(step){}
    bool operator < (const node &a) const {
        return step>a.step;
    }
};
struct Rest{
    int x,y;
}rest[60];
struct Tsure{
    int x,y;
}treasure[10010];
int dis[60][10010],whe[60],mmax,vis[105][105],duixiang[10500],viss[10500];
void addedge(int u,int v){
    edge[edn].u=u; edge[edn].v=v;
    edge[edn].next=p[u]; p[u]=edn++;
}
int gainpo(int x,int y){
    return (x-1)*m+y;
}

void init(){
    memset(whe,0,sizeof(whe));
    memset(duixiang,-1,sizeof(duixiang));
    edn=0;
    memset(p,-1,sizeof(p));
}
void bfss(int sx,int sy,int now){
    priority_queue<node> q;
    q.push(node(sx,sy,0));
    memset(vis,0,sizeof(vis));
    vis[sx][sy]=1;
    for(int i=0;i<10010;i++){
        dis[now][i]=inf;
    }
    while(!q.empty()){
        node a=q.top(); q.pop();
        dis[now][gainpo(a.x,a.y)]=a.step;
        for(int i=0;i<4;i++){
            int dx=a.x+dir[i][0],dy=a.y+dir[i][1];
            if(dx<=0||dy<=0||dx>n||dy>m||vis[dx][dy]||mp[dx][dy]=='#') continue;
            vis[dx][dy]=1;q.push(node(dx,dy,a.step+1));
        }
    }
}
int match(int x){
    for(int i=p[x];~i;i=edge[i].next){
        int v=edge[i].v;
        if(!viss[v]){
            viss[v]=1;
            if(duixiang[v]==-1||match(duixiang[v])){
                duixiang[v]=x;
                 return 1;
            }
        }
    }
    return 0;
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        init();
        int numtre=0;
        mmax=-1;
        for(int i=1;i<=n;i++)
            scanf("%s",mp[i]+1);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(mp[i][j]=='*'){
                    treasure[numtre].x=i,treasure[numtre++].y=j;
                }
                else if(mp[i][j]>='A'&&mp[i][j]<='Z'){
                    int th=mp[i][j]-'A'+1;
                    if(th>mmax) mmax=th;
                    whe[th]=1,rest[th].x=i,rest[th].y=j;
                }
                else if(mp[i][j]>='a'&&mp[i][j]<='z'){
                    int th=mp[i][j]-'a'+27;
                    if(th>mmax) mmax=th;
                    whe[th]=1,rest[th].x=i,rest[th].y=j;
                }
            }
        }
        int flag=0,nowid=1;
        for(int i=1;i<=mmax;i++){
            if(!whe[i]){
                flag=1;break;
            }
            bfss(rest[i].x,rest[i].y,i);
        }
        if(flag) {
            cout<<"-1"<<endl;
            continue;
        }
        for(int i=1;i<mmax;i++){
            int alldis=dis[i][gainpo(rest[i+1].x,rest[i+1].y)];
            if(alldis==inf){
                flag=1; break;
            }
            for(int j=0;j<numtre;j++){
                int dis1=dis[i][gainpo(treasure[j].x,treasure[j].y)];
                int dis2=dis[i+1][gainpo(treasure[j].x,treasure[j].y)];
                if(dis1+dis2==alldis) addedge(i,gainpo(treasure[j].x,treasure[j].y));
            }
        }
        if(flag){
            cout<<"-1"<<endl;
            continue;
        }
        int sum=0;
        for(int i=1;i<=mmax;i++){
            memset(viss,0,sizeof(viss));
            if(match(i)) sum++;
        }
        printf("%d\n",sum);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值