您的位置:首页 > 其它

最大费用循环流(帮助小罗拉,uva 1659)

2016-08-06 21:02 357 查看
用紫书上的第一种方法做的。

本来要找环使得分最大(即最大费用循环流),为了用最小费用流建模,就边权取反,然后找负环增广。(转换成最小费用循环流)

以下下有两个要点:

1、循环流没有最大流这个说法

事实上在算法运行时也只是找负圈,然后就对负圈进行增广,不存在源点与汇点,也不会对s-t进行增广,也就不会有所谓的最大流。

但其实算法运行完毕后是能够算出一个flow来的,这个flow叫啥我也不知道。但是最重要的是,这个flow是最小费用的副产品。即保证总费用一定最小,然后算出来的这个flow,这个flow却不一定是最大(嗯,后来仔细的想了想,其实flow就是增广的次数,因为可以反向增广,一个大负环也可能可以拆开重组成几个小负环,几个小负环也可能拆开拼凑成一个大负环,等等等等,但最终目的是为了让cost最小,所以这个flow没有任何意义,访问次序的不同导致多次拆合都可能会影响它的数值。)。而在最小费用最大流中,是优先满足flow最大,再满足cost最小。

2、找负环是Bellman-Ford的拿手好戏。

最小费用最大流寻增广路的方法就是Bellman-Ford,本意是为了在发现负环时及时退出。

我觉得就算是负环存在,也能找到最小费用最大流的。如:

u v cap cost

1 2 100 -1

2 1 100 -1

1 3 1 2

1->2->1就是一个负环。

而最小费用最大流是1->2->1->3.

费用为0,流量为1。

但为何发现负环要及时退出呢?

原因是这种算法是靠找最短路来进行增广的,而若存在负环,则无法找到最短路,因此这种算法失效,但其他算法却不一定。

以上是我的一些想法,不知道对不对。

关于找负环:

Bellman-Ford作为一种单源最短路算法,只能找到从s出发的负环。发现负环不代表s到每个点的最短路都不存在。另外,如果图中有其他负圈但是s无法到达这个负圈,则上面的算法也无法找到。

于是我傻呆呆的循环了所有的节点来找负环。。超时。。。

事实上只需要增加一个源点,给其他所有点连一条容量为1,费用为0的边就OK了。

做完这个优化后由于节点的访问顺序变了,暴露出了一个死循环,改正后就AC了。

后来发现第一次超时不是因为循环了所有节点,而是有没发现的死循环,幸好后来暴露出来了。

自己试了一下,事实上循环所有节点也只是多花了一点时间而已,离TLE还远着呢!

关于死循环:

我也不知道为什么会这样,只好修改了一下,慢一点但保证对。

代码

#include<stdio.h>
#include<vector>
#include<queue>
#include<string.h>
#include<limits>
#include<math.h>
#define maxn 110
using namespace std;

const double INF=(numeric_limits<double>::max)();

struct Edge
{
int from,to,cap;
double flow,cost;
Edge(int u,int v,int c,double f,double w):from(u),to(v),cap(c),flow(f),cost(w){}
};

struct MCMF
{
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
int inq[maxn];
double d[maxn];
int p[maxn];
double a[maxn];

void init(int n)
{
this->n=n;
for(int i=0;i<=n;i++) G[i].clear();
edges.clear();
}

void AddEdge(int from,int to,double cap,double cost)
{
edges.push_back(Edge(from,to,cap,0,cost));
edges.push_back(Edge(to,from,0,0,-cost));
m=edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}

bool BellmanFord(int s,double& flow,double& cost)
{
int cnt[maxn];
int k=-1;
memset(cnt,0,sizeof(cnt));
for(int i=0;i<n;i++) d[i]=INF;
memset(inq,0,sizeof(inq));
d[s]=0;inq[s]=1;p[s]=0;a[s]=INF;

queue<int>Q;
Q.push(s);
while(!Q.empty())
{
int u=Q.front();Q.pop();
inq[u]=0;
for(unsigned int i=0;i<G[u].size();i++)
{
Edge& e=edges[G[u][i]];
if(e.cap>e.flow&&d[e.to]>d[u]+e.cost)
{
d[e.to]=d[u]+e.cost;
p[e.to]=G[u][i];
a[e.to]=min(a[u],e.cap-e.flow);
if(!inq[e.to]){Q.push(e.to);inq[e.to]=1;if(++cnt[e.to]>n){k=u;goto here;}}
}
}
}
here:
if(k==-1) return false;
int vis[maxn];
memset(vis,0,sizeof(vis));
for(int u=k;;u=edges[p[u]].from)
{
vis[u]++;
if(vis[u]==2) {k=u;break;}
}
flow+=a[k];
edges[p[k]].flow+=a[k];
edges[p[k]^1].flow-=a[k];
cost+=edges[p[k]].cost;
for(int u=edges[p[k]].from;u!=k;u=edges[p[u]].from)
{
edges[p[u]].flow+=a[k];
edges[p[u]^1].flow-=a[k];
cost+=edges[p[u]].cost;
}
return true;
}

double MincostMaxflow(double & cost)
{
double flow=0;cost=0;
while(BellmanFord(n,flow,cost));
return flow;
/*double flow=0;cost=0;
for(int i=0;i<n;i++)
{
if(BellmanFord(i,flow,cost)) i--;
}
return flow;*/
}
};

struct pt
{
double x,y;
vector<int>vec;
}pts[maxn];

int n,x,y;

double DIST(int a,int b)
{
double x=pts[a].x-pts[b].x;
double y=pts[a].y-pts[b].y;
return sqrt(x*x+y*y);
}

int kase;

int main()
{
while(scanf("%d",&n),n)
{
scanf("%d %d",&x,&y);
for(int i=0;i<n;i++)
{
scanf("%lf %lf",&pts[i].x,&pts[i].y);
pts[i].vec.clear();
int temp;
while(scanf("%d",&temp),temp) pts[i].vec.push_back(temp-1);
}
MCMF mcmf;
mcmf.init(n);
for(int i=0;i<n;i++)
{
mcmf.AddEdge(n,i,1,0);
for(unsigned int j=0;j<pts[i].vec.size();j++)
{
mcmf.AddEdge(i,pts[i].vec[j],1,-x*DIST(i,pts[i].vec[j])+y);
}
}
double cost;
mcmf.MincostMaxflow(cost);
printf("Case %d: ",++kase);
if(cost==0) printf("%.2lf\n",cost);
else printf("%.2lf\n",-cost);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: