题目地址: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;
}

HDU 3468 Treasure Hunting(BFS+网络流之最大流)的更多相关文章

  1. 【网络流】 HDU 3468 Treasure Hunting

    题意: A-Z&&a-z 表示 集结点 从A点出发经过 最短步数 走到下一个集结点(A的下一个集结点为B ,Z的下一个集结点为a) 的路上遇到金子(*)则能够捡走(一个点仅仅能捡一次) ...

  2. HDU 3338 Kakuro Extension (网络流,最大流)

    HDU 3338 Kakuro Extension (网络流,最大流) Description If you solved problem like this, forget it.Because y ...

  3. HDU 4280 Island Transport(网络流,最大流)

    HDU 4280 Island Transport(网络流,最大流) Description In the vast waters far far away, there are many islan ...

  4. HDU 3641 Treasure Hunting(阶乘素因子分解+二分)

    题目链接:pid=3641">传送门 题意: 求最小的 ( x! ) = 0 mod (a1^b1*a2^b2...an^bn) 分析: 首先吧a1~an进行素因子分解,然后统计下每一 ...

  5. hdu 3641 Treasure Hunting 强大的二分

    /** 大意:给定一组ai,bi . m = a1^b1 *a2^b2 * a3^ b3 * a4^b4*...*ai^bi 求最小的x!%m =0 思路: 将ai 质因子分解,若是x!%m=0 那么 ...

  6. HDU 3605Escape(缩点+网络流之最大流)

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3605 本来打算昨天写两道题的,结果这个题卡住了,最后才发现是最后的推断条件出错了,推断满流的条件应该是 ...

  7. HDU 3416 Marriage Match IV (最短路径,网络流,最大流)

    HDU 3416 Marriage Match IV (最短路径,网络流,最大流) Description Do not sincere non-interference. Like that sho ...

  8. HDU 3081 Marriage Match II (网络流,最大流,二分,并查集)

    HDU 3081 Marriage Match II (网络流,最大流,二分,并查集) Description Presumably, you all have known the question ...

  9. HDU 3605 Escape (网络流,最大流,位运算压缩)

    HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...

随机推荐

  1. 算法分析-快速排序QUICK-SORT

    设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序.值得注意的 ...

  2. 打造坚固的安全的Linux服务器(ssh登录篇)

      Nov 3 01:22:06 server sshd[11879]: Failed password for root from 123.127.5.131 port 38917 ssh2Nov ...

  3. J2SE知识点摘记(二)

    1.    对象的声明 "类名 对象名 = new 类名();"例子:Person P;//先声明一个Person类的对象p p=new Person();//用new关键字实例化 ...

  4. C语言malloc和free实现原理

    以下是一段简单的C代码,malloc和free到底做了什么? int main() { char* p = (char*)malloc(32); free(p); return 0; } malloc ...

  5. 学javascript突发奇想,只用浏览器就能转换进制

    只需要三行就可以了 具体代码如下 <script> document.write(new Number(8).toString(2));//toSting方法可以转换任何进制 </s ...

  6. unity 距离某天还有多久

    距离某一天还有多久,简单的小例子. using UnityEngine; using System.Collections; using System; public class test : Mon ...

  7. 如何同时激活两个不同版本的MyEclipse 【MyEclipse2013和MyEclipse2014同时激活】

    激活一个MyEclipse的步骤,大家都会,在这里就不多说了,不会的可以看:http://jingyan.baidu.com/article/3ea51489cc14d452e71bba7a.html ...

  8. Linux学习之六-Yum命令的使用

    详细介绍一下yum命令的用法.如果你是一个Linux的初学者,一定会被软件的安装所困扰过,尽管RPM包解决了一定层度的问题,但有些RPM的包的依赖关系让人很是头疼.而YUM.APT等一些RPM包的管理 ...

  9. JAVA模板方法模式

    模板方法模式的结构 模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术. 模板方法模式需要开发抽象类和具体子类的设计师之间的协作.一个设计师负责给出一个算法的轮廓和骨架,另 ...

  10. sql日志损坏造成数据库置疑解决办法

    --如果确定是日志损坏造成,请用下面的方法恢复日志文件.--第一步--use mastergo sp_configure 'allow updates', 1reconfigure with over ...