您的位置:首页 > 理论基础 > 计算机网络

zju2676 Network Wars 分数规划+网络流

2013-08-29 20:36 183 查看
题意:给定无向图,每条边有权值,求该图的一个割集,是的该割集的平均边权最小

Amber的《最小割模型在信息学竞赛中的应用》中讲的很清楚了。

二分答案k,对每条边进行重新赋值为原边权-k,求最大流,

可看这里:http://hi.baidu.com/buaa_babt/item/a08fbb45599dc722fb89602a

二分枚举当前的平均边长l,对于边权<=l的直接加入当前最优割集,边权>l的将容量设为边权-l,加入到网络中,求出最小割的和sum,sum加上刚刚那些小于l的边(也是边权-l),如果大于0就意味着l不可作为最小平均边权,小于0就可以,当等于0时直接输出即可。一定要注意精度

注意是无向图,还有就是求st割,求解答案。

#define inf 0x3f3f3f3f
#define maxm 100000
#define maxn 10000
#define eps 1e-9
struct node
{
int u ;
int v,next,id;
double w;
void init(int u1,int v1,double w1)
{
u = u1;
v = v1;
w = w1;
}
};
node e1[maxn];
int head[maxn];
int cnt ;
int cnt1;
node edge[maxn];
int sgn(double x) {         //return -1 0 1
return x < -eps ? -1 : x > eps;
}
void init()
{
memset(head,-1,sizeof(head));
cnt = 0 ;
}
void add(int u,int v,int id,double w)
{
edge[cnt].u = u;
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].id = id;
edge[cnt].next = head[u];
head[u] = cnt ++ ;

edge[cnt].u = v;
edge[cnt].v = u;
edge[cnt].w = 0;
edge[cnt].id = id;
edge[cnt].next = head[v];
head[v] = cnt ++ ;
}

int dis[maxn];
int pre[maxn],cur[maxn],gap[maxn];
int s,t,nn;

int sap()
{
double flow,aug;
int u;
int flag;
int i;
flow=0;
aug=inf;
for(i=0; i<nn; i++)
{
cur[i]=head[i];
gap[i]=0;
dis[i]=0;
}
gap[s]=nn;
u=s;
pre[s]=s;
while(dis[s]<nn)
{
flag=0;
for(int &j=cur[u]; j!=-1; j=edge[j].next)
{
//cur[u]=j;
int v=edge[j].v;
if(edge[j].w>0&&dis[u]==dis[v]+1)
{
flag=1;
if(edge[j].w<aug)aug=edge[j].w;
pre[v]=u;
u=v;
if (u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
edge[cur[u]].w-=aug;
edge[cur[u]^1].w+=aug;
//why?解释偶数异或1为偶数+1,奇数异或1为奇数-1,
//显然我们存的边是从0开始存的,
//所以偶数,偶数+1是残量网格中的两条边(无向边)
}
aug=inf;
}
break;
}
}
if (flag) continue;
int mindis=nn;
for(int j=head[u]; j!=-1; j=edge[j].next)
{
int v=edge[j].v;
if (edge[j].w>0&&dis[v]<mindis)
{
mindis=dis[v];
cur[u]=j;
}
}
if (--gap[dis[u]]==0)//间隙优化
{
break;
}
dis[u]=mindis+1;
gap[dis[u]]++;
u=pre[u];
}
return flow;
}
bool xxx[maxn];
int n,m;
double judge(double lda)
{
memset(xxx,0,sizeof(xxx));
init();
double res = 0.0;
for(int i = 1; i <= m  ; i ++)
{
double tmp ;
tmp = e1[i].w - lda;
if( tmp >=0 )
add(e1[i].u,e1[i].v,i,tmp) , add(e1[i].v,e1[i].u,i,tmp); // 注意
else
{
res += tmp;
xxx[i] = 1 ;
}
//if(sgn(tmp) < 0 )
//    res += tmp ;
//else add(e1[i].u,e1[i].v,i,tmp);
}
s = 1;
t = n ;
nn = t + 2;
res += sap();
return res;
}
queue<int> q;
int col[maxn];
bool vis[maxn];
void bfs(int st,int color)
{
memset(vis,0,sizeof(vis));
memset(col,0,sizeof(col));
while(!q.empty()) q.pop();
q.push(st);
vis[st] = 1;
col[st] = color;
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(sgn(edge[i].w) > 0 && vis[v] == 0 )
{
vis[v] = 1;
col[v] = color;
q.push(v);
}
}
}
return ;
}
vector<int> ans ;
void getst(double lda)
{
bfs(1,1);
ans.clear();
for(int i = 1 ; i <= m ; i ++ )     // 注意
{
if(!xxx[i])
{
if(col[e1[i].u] != col[e1[i].v] )
{
ans.push_back(i);
}
}
else ans.push_back(i);
}
int size = ans.size();
sort(ans.begin(),ans.end());
printf("%d\n",size);
for(int i = 0; i < size ; i++ )
{
printf("%d",ans[i]);
if(i != size - 1 ) printf(" ");
else printf("\n");
}
}
int main()
{
int cas;
cas = 0 ;
while(scanf("%d%d",&n,&m)!=EOF)
{
cnt1 = 1 ;
int u,v;
double w;
double L,R;
L = eps;
for(int i = 1 ; i <= m; i ++ )
{
scanf("%d%d%lf",&u,&v,&w);
e1[i].init(u,v,w);
R = max(R , w);
}
double mid ;
for(int i = 0 ; i < 101 ; i ++ )
// while( R - L > eps )
{
mid = ( L + R ) / 2.0;
double tmp = judge(mid);
if(sgn(tmp ) > 0 )    // 判断
L = mid + eps;
else R = mid;
}
if(cas != 0 ) printf("\n");
cas ++ ;
judge(L);
getst(L);
}
return 0;
}


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