问题描述:
机器人Rob可在一个树状路径上自由移动。给定树状路径T上的起点s 和终点t,机器
人Rob要从s运动到t。树状路径T上有若干可移动的障碍物。由于路径狭窄,任何时刻在相连的顶点编号。
结果输出:
程序运行结束时,将计算出的机器人最少移动次数输出到文件output.txt 中。如果无法
将机器人从起点移动到终点,输出“No solution!”。
输入示例 : 输出示例:
5 0 3 3
1 1 2
1 1 2
1 3 0 1 3
0 2 2 4
1 1 3
初步分析:
刚拿到题目时,感觉一点头绪也没有。想了很久,被迫上网百度,结果网上也没有解题报告,说这题是个经典难题,不会做。唯一可以确定的信息是这题是最小费用流。
好吧,虽然咱也是个菜鸟,但是也不能看到难题就怕是吧。所以对着屏幕想了N久,想出了一个自以为很漂亮的解法。
我是这样建模的,首先我认为这是一个树形的路径,所以起点和终点只有唯一的路线,所以要把起点和终点的障碍物都移走,首先判断在起终点的障碍数目和这条线之外的没有障碍的顶点数做比较,如果大于,直接No Solution。然后,建模,任意顶点之间若相连,容量无穷,费用为1。创建S,T点,S点连接所有的起终点之间的有障碍物的顶点,容量为1,费用为1。T点连接所有的起终点那条线之外的所有没有障碍物的顶点,容量为1,费用为1。
然后求一次最小费用流。这样就等同与把所有的线内的障碍物都移到了线外。有人会质疑了,如果线外也有障碍物拦着,后面才是空的顶点,怎么算。不用担心,就当他不存在。因为可以等效于把那个障碍物移到指定点,然后把线内的障碍物移到那个点。路程是一样的,这样就等效于“穿过”了障碍物,所以在这题里,障碍物和障碍物之间是不构成阻碍的。想到这里似乎问题都解决了。
我迫不及待的写出代码,调试了一翻,完成了我的功能。当我把测试数据带入的时候,我先试了最大的2个规模的数据,一个是1000个点的,一个是500个点的。卧槽,都过了。当时把我给乐的。然后用16个点的数据和19个点的数据一测,NND,都不对。我把16个点的数据画了一个图,终于明白了,我的代码缺陷在哪里。
因为机器人是不能被障碍物“穿过的”,所以如果线内的点想要移到机器人后面的空点,是要有一个很复杂的过程的。后来又发现一个问题。线内的障碍物数目大于线外的空点数也是可解的。因为可以把机器人暂时移到分叉的另一个点上,然后把终点前的障碍物移到起点附近,这样在线内也是允许有障碍物的。
后来我又想,这个问题可以转化成DP,f(s,t,n)表示以s为起点t为终点的线内有n个障碍物的路线机器人所要走的步数。之前的分叉暂存的思想就可以转化为
f(s,t,n)=min{f(s,s',n')+f(s',t,n-n')},边界条件是f(a,b,0)=a到b的路程,可是具体的实现还是不会,而且这样的想法不能证明是否正确,奈何本人太菜,没学过树上的DP,对网络流也是刚刚起步,故到了这里,决定放弃该题。希望有大牛能指出我的不足,或能用这个思想解出该题。
这题限于目前的水平,我只能先放着,半年后再拿出来,看能否解决。
下面是我的实现的,障碍物能”穿过“机器人的代码:
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 1010;
const int INF = 1<<30;
int s,t,n;
int S,T;
int fa[maxn],d[maxn],p[maxn],a[maxn];
bool visit[maxn],inqueue[maxn];
int in[maxn],num=0;
struct edge{
int from,to,cap,flow,cost;
edge(int a,int b,int c,int d,int f):from(a),to(b),cap(c),flow(d),cost(f){}
};
vector edges;
vector g[maxn];
int bsearch(int key)//二分查找
{
int l=0,r=num-1;
while(l<=r){
int mid=(l+r)>>1;
if(in[mid]==key) return true;
else if(in[mid] q;
q.push(s);
visit[s]=true;
while(!q.empty()){
bool flag=false;
int x=q.front();q.pop();
for(int i=0;iq;
q.push(S);
while(!q.empty()){
int x=q.front();q.pop();inqueue[x]=false;
for(int i=0;ie.flow&&d[e.to]>d[x]+e.cost){
d[e.to]=d[x]+e.cost;
p[e.to]=g[x][i];
a[e.to]=min(a[x],e.cap-e.flow);
if(!inqueue[e.to]){ inqueue[e.to]=true;q.push(e.to); }
}
}
}
if(d[T]==INF) return false;
flow+=a[T];
// printf("%d %d %d\n",d[T]-2,a[T],(d[T]-2)*a[T]);
cost+=(d[T]-2)*a[T];//减去S和T的费用,则为移动障碍的费用
int x=T;
while(x!=S){
edges[p[x]].flow+=a[T];
edges[p[x]^1].flow-=a[T];
x=edges[p[x]].from;
}
return true;
}
int mincost()
{
int flow=0,cost=0;
while(bellman(flow,cost));
return cost;
}
int main()
{
scanf("%d%d%d",&n,&s,&t);
S=n;T=n+1;
int index=0,index2=0;
int a[maxn],b[maxn];
int sum1=0,sum2=0;
for(int i=0;i