【分数规划总结】周测图论1 环 & CODEVS 1183 泥泞的道路

来源:互联网 发布:如何做一名网络写手 编辑:程序博客网 时间:2024/05/18 02:34

(s1+s2+…+sn)/(t1+t2+…+tn) = ans
即s1-t1*ans+s2-t2*ans+…+sn-tn*ans = 0
当需求比值解时考虑分数规划,二分答案求解。根据题目要求向上二分或向下二分,利用spfa判正/负环。


定义环的伸展度为这个环上所有边的距离之和与环上边的总数的比值,给出一个n个节点,m条边的有向图,每条边有一个属性距离,求图中伸展度最小的有向环。
输入说明:
第一行2个正整数n、m。
接下来m行每行3个正整数u,v,d,表示一条由u到v距离为d的单向道路。

输出说明:四舍五入,输出1个7位小数表示最小的伸展度。

样例输入:
2 2
1 2 1
2 1 2

样例输出:
1.5000000
数据说明:
对于20%的数据,n<=100,m<=1000
对于40%的数据,n<=1000,m<=-5000
对于100%的数据,n<=3000,m<=10000

数据保证至少有一个环

//二分+dfs版spfa判负环,因为是判负环所以d初值为0,dfs时要循环所有的点,防止漏。//负环条件是dfs是搜到的点仍在队列中。 #include<cstdio>#include<algorithm>#include<cstring>#include<iostream>using namespace std;const double eps = 1e-9;const int inf = 0x3f3f3f3f;const int maxn = 3030;const int maxm = 10010;int n, m, tot, f;int st[maxn], in[maxn];double d[maxn];struct node{    int to, w, next;    double wt;} edge[maxm];void ini(int u, int v, int d){    edge[++tot].to = v;    edge[tot].w = d;    edge[tot].next = st[u];    st[u] = tot;}void spfa(int rt){    in[rt] = 1;    for(int i = st[rt]; i > 0; i = edge[i].next){        int v = edge[i].to;        if(d[v] > d[rt] + edge[i].wt){//存在负值才更新距离。             if(in[v]){//再次到v比原来松弛过的距离还短,说明有负环。                 f = 1;                 return;            }            else{                d[v] = d[rt] + edge[i].wt;                spfa(v);            }        }    }    in[rt] = 0;}bool check(double x){    memset(in, 0, sizeof(in));    memset(d, 0, sizeof(d));    for(int i = 1; i <= tot; i++)        edge[i].wt = (double)edge[i].w - x;    f = 0;    for(int i = 1; i <= n; i++){        spfa(i);        if(f)   return f;    }    return f;}int main(){    cin >> n >> m;    for(int i = 1, u, v, d; i <= m; i++){        cin >> u >> v >> d;        ini(u, v, d);    }    double l = 0, r = 10000000, mid;    while(r - l > eps){        mid = (l+r) / 2;        if(check(mid))  r = mid;        else l = mid;    }    printf("%.7lf\n", r);    return 0;}

CODEVS 1183 泥泞的道路

//二分答案BFS找正环。 #include<cstdio>#include<queue>#include<algorithm>#include<cstring>#include<iostream>using namespace std;const double eps = 1e-4;const int inf = 0x3f3f3f3f;const int maxn = 210;int n, p[maxn][maxn], t[maxn][maxn], in[maxn], hash[maxn];double f[maxn][maxn];double d[maxn];bool spfa(){    queue<int> q;    d[1] = 0;    in[1] = 1;    q.push(1);    while(!q.empty()){        int u = q.front();        q.pop();        in[u] = 0;        for(int i = 1; i <= n; i++){            if(p[u][i] && d[i] < d[u] + f[u][i]){                d[i] = d[u] + f[u][i];                if(!in[i]){                    in[i] = 1;                    q.push(i);                    hash[i]++;                    if(hash[i] >= n)    return true;//BFS版SPFA的判环条件,入队 >= n次。                 }            }        }    }    if(d[n] > 0)    return true;//注意要添这一步,更新到n大于0,说明可以更优。     return false;}bool check(double x){    memset(f, 0, sizeof(f));    memset(in, 0, sizeof(in));    memset(hash, 0, sizeof(hash));    for(int i = 0; i <= n; i++)        d[i] = -inf;    for(int i = 1; i <= n; i++)        for(int j = 1; j <= n; j++)            f[i][j] = (double)p[i][j] - t[i][j] * x;    if(spfa())  return true;    else return false;}int main(){    cin >> n;    for(int i = 1; i <= n; i++)        for(int j = 1; j <= n; j++)            cin >> p[i][j];    for(int i = 1; i <= n; i++)        for(int j = 1; j <= n; j++)            cin >> t[i][j];    double l = 0, r = 100000, mid;    while(r - l > eps){        mid = (l+r) / 2;        if(check(mid))  l = mid;        else r = mid;    }    printf("%.3lf\n", l);    return 0;}
原创粉丝点击