查分约束uva

来源:互联网 发布:制作结婚证软件 编辑:程序博客网 时间:2024/04/29 18:51

You are given a weighted directed graph with n vertices and m edges. Each cycle in the graph has a

weight, which equals to sum of its edges. There are so many cycles in the graph with different weights.

In this problem we want to find a cycle with the minimum mean.
Input
The first line of input gives the number of cases, N. N test cases follow. Each one starts with two
numbers n and m. m lines follow, each has three positive number a, b, c which means there is an edge
from vertex a to b with weight of c.
Output
For each test case output one line containing Case #x: followed by a number that is the lowest mean
cycle in graph with 2 digits after decimal place, if there is a cycle. Otherwise print No cycle found..
Constraints
• n ≤ 50
• a, b ≤ n
• c ≤ 10000000
Sample Input
2
2 1
1 2 1
2 2
1 2 2
2 1 3
Sample Output
Case #1: No cycle found.

Case #2: 2.50

题意:就是让求 权值最小的环  的平均权值,小数保留两位;

    最开始我的思路错了,认为凡是环肯定是联通分量,找到所有联通分量求最小平均值,但是WA,因为虽然环是联通分量,但是联通分量不代表环啊!!!!

问了一下别人,二分加bellman—Ford算法,该算法是求有没有负环的,

bool find_negative()///查找负环{    memset(d,0,sizeof(d));    for(int i=1; i<=n; i++)    {        for(int j=0; j<m; j++)        {            Edge e=edge[j];            if(d[e.v]>d[e.u]+e.w)            {                d[e.v]=d[e.u]+e.w;                if(i==n)                    return true;///存在负环            }        }    }    return false;}
一直更新最短距离,如果存在负环,他会不停的更新下去,所以可以用来求负环,
然后我们用二分的方法找最小的环均值,在一个图中最多有一个 环权值最小的环,每次把所有边权值减掉一个数,二分查找,直到找到权值为0的临界环,那么就找到了最小 环均值;
见我的代码:
<pre name="code" class="cpp">#include <iostream>#include <stdio.h>#include <string.h>using namespace std;const int maxn=5500,maxm=5050,inf=0x3f3f3f3f;struct Edge{    int u,v;    double w;} edge[maxm],e[maxm];int n,m;double d[maxn];bool find_negative()///查找负环{    memset(d,0,sizeof(d));    for(int i=1; i<=n; i++)    {        for(int j=0; j<m; j++)        {            Edge e=edge[j];            if(d[e.v]>d[e.u]+e.w)            {                d[e.v]=d[e.u]+e.w;                if(i==n)                    return true;            }        }    }    return false;}double min_(double a,double b){    if(a<b)        return a;    return b;}double max_(double a,double b){    if(a<b)        return b;    return a;}int main(){    int t,T=0;    double mid, r,l;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&m);        r=0.0;        l=inf*1.0;        for(int i=0; i<m; i++)        {            scanf("%d%d%lf",&edge[i].u,&edge[i].v,&edge[i].w);            e[i].w=edge[i].w;///备份数据            l=min_(l,e[i].w);///二分所用            r=max_(r,e[i].w);        }        for(int i=0; i<m; i++)            edge[i].w-=(r+1);///先把所有边减一个最大值        if(!find_negative())///判断有没有负环        {            printf("Case #%d: No cycle found.\n",++T);            continue;        }        for(int i=0; i<m; i++)            edge[i].w=e[i].w;        for(int i=0; i<100; i++)///二分查找        {            mid=(l+r)*0.5;            for(int i=0; i<m; i++)                edge[i].w-=mid;            if(find_negative())                r=mid;            else                l=mid;            for(int i=0; i<m; i++)                edge[i].w=e[i].w;        }        printf("Case #%d: %.2lf\n",++T,l);    }    return 0;}


You are given a directed graph G(V, E) with a set of vertices and edges. Each edge (i, j) that connectssome vertex i to vertex j has an integer cost associated with that edge.Define the operation Halum(v, d) to operate on a vertex v using an integer d as follows: subtractd from the cost of all edges that enter v and add d to the cost of every edge that leaves v.As an example of that operation, consider graph G that has three vertices named (1, 2, 3) and twoedges. Edge (1, 2) has cost -1, and edge (2,3) has cost 1. The operation Halum(2, −3) operates onedges entering and leaving vertex 2. Thus, edge (1, 2) gets cost -1-(-3)=2 and the edge (2, 3) gets cost1 + (-3) = -2.Your goal is to apply the Halum function to a graph, potentially repeatedly, until every edge in thegraph has at least a certain cost that is greater than zero. You have to maximize this cost.InputTwo space-separated integers per case: V (V ≤ 500) and E (E ≤ 2700). E lines follow. Each linerepresents a directed edge using three space-separated integers (u, v, d). Absolute value of cost can beat most 10000.OutputIf the problem is solvable, then print the maximum possible value. If there is no such solution print‘No Solution’. If the value can be arbitrary large print ‘Infinite’Sample Input2 11 2 102 11 2 -103 31 2 42 3 23 1 54 52 3 44 2 53 4 23 1 01 2 -1Sample OutputInfiniteInfinite31
本题题意: 有一种操作Halum(x,d),表示将指向x顶点的边权值加上d,将x指向其他点的边的权值减去d,让你重复尝试这种操作,使图中所有边权值大于0,并且尽量使权值最小的边的权值最大化,如果权值最小边可以是无穷大,输出Infinite,如果不能实现所有边权值大于0,输出No Solution,其他情况输出最小边权值,Halum(x,d)中的d>=1的整数;
这道题目和上一道题目类似,当有环时,就会存在权值最小的边了,试想一下,在一个环中围绕所有顶点无论如何加减,和始终不变,在这个环中边权值最小就是  和/边(int)向下取整!! 那么这道题就好做了,依旧二分,只是精度不是小数,而是int,在判断是否是 “No solution”时,对每条边进行一次减1操作,因为0环也是非负环啊,无论把边权值减多大都不会出现负环的就是“Infinte”的情况,其他情况就是输出最小环权值均值啦
<pre name="code" class="cpp">#include <iostream>#include <stdio.h>#include <string.h>using namespace std;const int maxn=5500,maxm=5050,inf=0x3f3f3f3f;struct Edge{    int u,v,w;} edge[maxm],e[maxm];int n,m;int d[maxn];bool find_negative()///查找负环{    memset(d,0,sizeof(d));    for(int i=1; i<=n; i++)    {        for(int j=0; j<m; j++)        {            Edge e=edge[j];            if(d[e.v]>d[e.u]+e.w)            {                d[e.v]=d[e.u]+e.w;                if(i==n)                    return true;///存在负环            }        }    }    return false;}int main(){    int t,T=0;    int  mid, r,l;    while(scanf("%d%d",&n,&m)!=-1)    {        r=0;        l=inf;        for(int i=0; i<m; i++)        {            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);            e[i].w=edge[i].w;///备份数据            l=min(l,e[i].w);///二分所用            r=max(r,e[i].w);        }        for(int i=0; i<m; i++)///减1操作,判断起始时有没有负环和0环            edge[i].w-=1;     ///0环需要减1 才能判断出来,0环不属于负环        if(find_negative())        {            printf("No Solution\n");            continue;        }        for(int i=0; i<m; i++)            edge[i].w+=1;        for(int i=0; i<m; i++)            edge[i].w-=(r+1);///先把所有边减一个最大值        if(!find_negative())///判断有没有负环        {            printf("Infinite\n");            continue;        }        for(int i=0; i<m; i++)            edge[i].w=e[i].w;        for(int i=0; i<100; i++)///二分查找        {            mid=(l+r)/2;            for(int i=0; i<m; i++)                edge[i].w-=mid;            if(find_negative())                r=mid;            else                l=mid;            for(int i=0; i<m; i++)                edge[i].w=e[i].w;        }        printf("%d\n",l);    }    return 0;}



0 0
原创粉丝点击