您的位置:首页 > 其它

UVA 1659 Help Little Laura 帮助小劳拉 (最小费用流,最小循环流)

2015-07-19 18:32 573 查看
(同时也是HDU 2982,UVA的数据多)

题意:平面上有m条有向线段连接了n个点。你从某个点出发顺着有向线段行走,给走过的每条线段涂一种不同的颜色,最后回到起点。你可以多次行走,给多个回路涂色(要么不涂色,要么就至少给一个回路上的边全部涂色)。可以重复经过一个点,但不能重复经过一条有向线段。如下图所示的是一种涂色方法(虚线表示未涂色,即每次都可以从任意点出发染色)。每涂一个单位长度将得到X分,但每使用一种颜色将扣掉Y分。假设你拥有无限多种的颜色,问如何涂色才能使得分最大?输入保证若存在有向线段u -> v,则不会出现有向线段v -> u。

  n <= 100,m <= 500,1 <= X,Y <= 1000。

  对于坐标(x,y)0 <= x,y <= 1000。

#include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define INF 0x7f7f7f7f
using namespace std;
const int N=200;
int x
, y
, rudu
;
int earn, lost, n;
vector<int> vect
, vec
;
double sum;

struct node
{
int from, to, cap, flow;
double val;
node(){};
node(int from,int to,double val,int cap,int flow):from(from),to(to),val(val),cap(cap),flow(flow){};
}edge[90000];
int edge_cnt;

void add_node(int from,int to,double val,int cap,int flow)
{
edge[edge_cnt]=node(from, to, val, cap, flow );
vec[from].push_back(edge_cnt++);
}

void build_graph()
{
for(int i=1; i<=n; i++)
{
for(int j=0; j<vect[i].size(); j++)
{
int t=vect[i][j];
double v= lost - sqrt( pow(x[i]-x[t],2)+pow(y[i]-y[t],2) )*earn;

if(v<0)
{
add_node(t, i, -v, 1, 0 );  //反边
add_node(i, t, v, 0, 0 );
sum+=v;
rudu[t]++,rudu[i]--;
}
else
{
add_node(i, t, v, 1, 0);
add_node(t, i, -v, 0, 0);
}
}
}
for(int i=1; i<=n; i++)
{
if(rudu[i]>0)
{
add_node(0, i, 0, rudu[i], 0);
add_node(i, 0, 0, 0, 0);
}
if(rudu[i]<0)
{
add_node(i, n+1, 0, -rudu[i], 0);
add_node(n+1, i, 0, 0, 0);
}
}
}

int flow
, path
, inq
;
double cost
;

double spfa(int s,int e)
{
deque<int> que(1,s);
cost[s]=0;
flow[s]=INF;
inq[s]=1;
while(!que.empty())
{
int x=que.front();
que.pop_front();
inq[x]=0;
for(int i=0; i<vec[x].size(); i++)
{
node e=edge[vec[x][i]];
if(e.cap>e.flow && cost[e.to]>cost[e.from]+e.val )
{
flow[e.to]=min(flow[e.from],e.cap-e.flow);
cost[e.to]=cost[e.from]+e.val;
path[e.to]=vec[x][i];
if(!inq[e.to])
{
inq[e.to]=1;
que.push_back(e.to);
}
}
}
}
return cost[e];
}

double mcmf(int s,int e)
{
double ans_cost=0.0;
while(true)
{
memset(flow,0,sizeof(flow));
memset(inq,0,sizeof(inq));
memset(path,0,sizeof(path));
for(int i=0; i<=e; i++)   cost[i]=1e39;

double tmp=spfa(s,e);    //返回费用
if(tmp>1e38)    return  ans_cost;
ans_cost+=tmp;

int ed=e;
while(ed!=s)
{
int t=path[ed];
edge[t].flow+=flow[n+1];
edge[t^1].flow-=flow[n+1];
ed=edge[t].from;
}
}
}

int main()
{
freopen("input.txt", "r", stdin);
int b, j=0;
while(scanf("%d", &n), n)
{
scanf("%d%d",&earn,&lost);
for(int i=0; i<=n+1; i++)   vect[i].clear();
for(int i=0; i<=n+1; i++)   vec[i].clear();
memset(edge,0,sizeof(edge));
memset(rudu,0,sizeof(rudu));
edge_cnt=0;
sum=0;

for(int i=1; i<=n; i++)
{
scanf("%d%d",&x[i],&y[i]);
while(scanf("%d",&b), b)    vect[i].push_back(b);   //原图邻接表
}
build_graph();
printf("Case %d: %.2f\n", ++j,  -(mcmf(0,n+1)+sum)+0.0000001 );
}
return 0;
}


AC代码

[align=CENTER] [/align]
[align=CENTER] [/align]
[align=CENTER] [/align]
[align=CENTER] [/align]
[align=CENTER] [/align]
[align=CENTER] [/align]
[align=CENTER] [/align]
[align=CENTER] [/align]
[align=CENTER] [/align]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: