您的位置:首页 > 其它

Codeforces 267C 高斯消元解方程

2013-02-03 17:59 381 查看
题目链接

首先,这个题还是蛮有意思的,,,

其次,一个sb的bug整了我一下午

题意:给出一个流量网络,告诉你每条边流量的上限,每个点(除了源点和汇点)都满足流量平衡,即流进 = 流出 ,还有一个关键的条件是对于任意的x y,从x走到y的流量和相等,流量和为从x到y每条边的流量相加(有正有负)。最后让你输出一种网络流的方案,使得总的流量最大

对于任意两个点,不管走哪条路径,流量和都是定值,这个有点类似于物理中的势能,从一个高度到达另一个高度,势能差不变,借此思路,可以设每个点的势能为x[i],那 边i j之间的流量就为x[j] - x[i],由每个点都满足流量守恒(除源汇外),可以列出n-2个方程来,举个例子,对于i这个点,枚举所有的邻接点j

x[i] - x[j1] + x[i] - x[j2] + x[j3] - x[i]  .... = 0 (要分 i->j  ,还是 j->i ,相应的系数就++ -- ) 

然后x1 和 xn随便设两个常数就好了,假设设为1 2 。

这样构造好方程解出来一组可行解,是忽略了每条边的流量限制的,现在,将每条边的流量限制放进去,可以算出每条边最大的容量

解是成比例的。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define _abs(x) ((x)>0?(x):-(x))
#define REP(i,n) for(int i=0;i<n;i++)
const int M = 5010;
const int N = 110 ;
int u[M] , v[M] , c[M];;
int  fa
, f
;
int find(int a){return fa[a]==a?a:fa[a]=find(fa[a]);}
double a

, b
, x
;
void linear_equation(int n) //  sum(a[i][j] * x[j]) = b[i];
{
REP(i,n) {
int p = i;
for(int j = i; j < n; j++) if(_abs(a[j][i]) > _abs(a[p][i])) p = j;
if(fabs(a[i][i]) < 1e-6) continue;//special judge,有些点可能不在点集中,会被0除
if(p != i){ REP(j,n) swap(a[i][j],a[p][j]); swap(b[i],b[p]); }
REP(j,n) if(j != i) {
double con = - a[j][i] / a[i][i];
for(int k = i; k < n; k++) a[j][k] += con * a[i][k];
b[j] += con * b[i];
}
}
REP(i,n) x[i] = b[i] / a[i][i];
}
int main()
{
int n , m;
scanf("%d%d",&n,&m);
REP(i,m) {
scanf("%d%d%d",&u[i],&v[i],&c[i]); u[i] -- ; v[i] --;
if(!f[u[i]]) f[u[i]]=1,fa[u[i]]=u[i];
if(!f[v[i]]) f[v[i]]=1,fa[v[i]]=v[i];
fa[find(u[i])] = find(v[i]);
a[u[i]][v[i]]--,a[u[i]][u[i]]++;
a[v[i]][u[i]]--,a[v[i]][v[i]]++;
}
if(!f[0] || !f[n-1] || find(0)!=find(n-1))	 {
REP(i,m+1) printf("0.000000000000000\n");
return 0;
}
REP(i,n) a[0][i] = 0,a[n-1][i]=0;
b[0] = 1; b[n-1] = 2;a[n-1][n-1] = 1; a[0][0]=1;
linear_equation(n);
double ing = 1e50;
double tmp[M];
REP(i,m)	ing = min(ing,(double)c[i]/fabs(x[u[i]]-x[v[i]]));
REP(i,n) x[i] *= ing;
double ans = 0;
REP(i,m) if(u[i]==0||v[i]==0) ans+=_abs(x[u[i]]-x[v[i]]);
printf("%.10lf\n",ans);
REP(i,m)  printf("%.10lf\n",x[v[i]]-x[u[i]]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: