hdu4818 RP problem

RP problem

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 884    Accepted Submission(s): 261


Problem Description
  As an ACMer, you must have heard of the legend of Ren Pin (RP), which means a person’s lucky degree. Neither can RP be created, nor eliminated without foundation. It can only be transferred from one person to another. Moreover, everyone has his social circle. It’s guaranteed that each person has at least one friend and he cannot be the friend of himself. The relationship is directed. In RP system, one’s RP is transferred from himself to all of his friends uniformly every day. For example, A has three friends, B, C and D and his current RP is 1. In tomorrow, 1/3 of his RP will be transferred to B, 1/3 to C and 1/3 to D and RP from those treat him as friends will be transferred to him as well.

  On the other hand, the god in charge of the RP system is tired of the transferring RP from one person to another every day. Making the assumption that the total amount of RP is 1, he wants to know whether there is a stable distribution in RP system, so that by reallocating the RP of each person, he can lighten his workload. Stable distribution means if the structure of social network keeps unchanged, no matter how many days pass by, everyone’s RP keeps unchanged. You will see an example as follows. For the ease of presentation, let “X->Y” denotes X takes Y as his friend. There are only three persons A, B and C in the world with A->B, B->C, C->A and C->B. If the current RPs of A, B, C are 0.2, 0.4, 0.4 respectively, then the RPs will still be 0.2, 0.4, 0.4 in tomorrow. It’s obviously that the distribution keeps unchanged no matter how many days pass by, so (0.2, 0.4, 0.4) is a stable distribution. However, if the current RPs of A, B, C are 0.3, 0.3, 0.4, respectively, then the RPs will be 0.2, 0.5, 0.3 in tomorrow, so (0.3, 0.3, 0.4) is not a stable distribution. The god wonders, for a given a social network, how many stable distributions exist?

  Furthermore, if there is one and only one stable distribution, your friend A, who is lack of luck, wants to know whether he can increase his RP by making one more new friend. More specifically, letting RP(A, G) be the RP of A in the stable distribution for a network G, the RP of A after adding A->X to G is RP(A, G \/ {A->X}). Your friend A wants to know if there exists a person X, such that RP(A, G \/ {A->X}) is strictly larger than RP(A, G). For example, there are four persons A, B, C, D in the world with A->B, B->C, C->A, D->A. The only one stable distribution is (1/3, 1/3, 1/3, 0). If A->D is added to the network, the stable distribution will be (2/5, 1/5, 1/5, 1/5) and 2/5 > 1/3, so A can increase his RP by making friend with D. If there are multiple qualifying persons, your friend A wants to know which one can increase his RP to the maximum extent.
 

Input
The first line of input contains an integer T (T ≤ 50) indicating the number of datasets. Each dataset starts with two integers n and m (n ≤ 100, n ≤ m ≤ n*(n-1)), where n and m indicate the number of persons and the number of relationships, respectively. Next m lines describe the relationships in the social network. Each of these lines will contain two integers u and v (0 ≤ u, v < n), indicating u->v.
 

Output
For each test case, output a single line. If the number of stable distributions is infinite, print “INF”, otherwise, print the number of stable distributions. If there is only one stable distribution, print the person whom your friend A can increase the most RP by making friend with. If there exists multiple such persons, print the one with the smallest ID. However, if no person satisfies the requirement, print “-1”.

Your friend A’s ID is always (n-1).
 

Sample Input
 
 
3 4 4 0 1 1 0 2 3 3 2 3 3 0 1 1 2 2 0 3 3 0 1 1 0 2 1
 

Sample Output
 
 
INF 1 1 1 -1
 

Source

2013 Asia Regional Changchun 


题解:确实是一个好题。

题意:一个有向图 图中所有结点的权值和为1 每个结点都会把自己的权值均分给自己相邻的结点 如果经过一轮分配后 各个结点的权值不变 则称这个图是稳定的 给你一个这样的图 问你如何分配各个点的权值 使得这个图是稳定的 输出分配方案的种类数 如果方案唯一 又问你是否可以添加一条从n-1到其它某个点的有向边 使得n-1这个点的权值最大化 并输出所连接的那个点

思路:不难想到这道题是高斯消元 公式也比较好列 a[i][i]=-1 n个方程n个未知数 其中有一个方程式没用的 因为这n个方程是解不出答案的 还有一个方程就是所有点的权值和为一 这样列出方程后如果无解 就说明有无穷多个解 否则只有一解 如果暴力枚举添加的边然后跑n次高斯消元 复杂度为O(n^4) 会超时 加一步优化即可解决 观察发现所做的n次高斯消元的前n-1列都是相同的 也就是说做了很多无用功 而高斯消元只做min(row, col)次消元 row是方程个数 col是未知数个数 每次只消一列 也即是说最终只会消除前row-1列 因此后面的每一列并不会彼此影响 故只需将这n个方程组的最后一列加到一个方程组里 在一个矩阵中即可跑出所有n次的结果即可


代码:

#include<cstdio>  
#include<cstring>  
#include<iostream>  
#include<algorithm>  
#include<cstdlib>  
#include<queue>  
#include<vector>  
#include<cmath>  
using namespace std;  
const int N = 300;  
const int INF=0x7fffffff;  
#define eps 1e-9  
double A[N][N];  
double x[N];  
int g[N][N],d[N];  
vector<int>edge[N];  
int add[N];  
bool Gauss(int equ,int var){  
    int row,col;  
    for(row=col=0;row<equ&&col<var;col++,row++){  
        int max_r=row;  
        for(int i=row+1;i<equ;i++){  
            if(fabs(A[max_r][col])<fabs(A[i][col])){  
                max_r=i;  
            }  
        }  
        if(fabs(A[max_r][col])<eps)return 0;  
        if(max_r!=row){  
            for(int i=col;i<var;i++){  
                swap(A[max_r][i], A[row][i]);  
            }  
        }  
        for(int i=col+1;i<var;i++){//将col+1~var化简  
            A[row][i]/=A[row][col];  
        }  
        A[row][col]=1;  
        for(int i=row+1;i<equ;i++){  
            if(fabs(A[i][col])<eps)continue;  
            for(int j=col+1;j<var;j++){  
                A[i][j]+=A[row][j]*(-A[i][col]);  
            }  
            A[i][col]=0;  
        }  
    }  
    return 1;  
}  
int main(){  
    int T;  
    scanf("%d",&T);  
    while(T--){  
        int n,m;  
          
        scanf("%d%d",&n,&m);  
          
        for(int i=0;i<n;i++)  
            edge[i].clear();  
        memset(d,0,sizeof(d));  
        memset(g,0,sizeof(g));  
        memset(A, 0, sizeof(A));  
          
        for(int i=0;i<m;i++){  
            int u,v;  
            scanf("%d%d",&u,&v);  
            if(u!=v)g[u][v]=1;  
        }  
        for(int i=0;i<n;i++){  
            for(int j=0;j<n;j++){  
                if(i!=j&&g[i][j]==1){  
                    d[i]++;  
                    edge[j].push_back(i);  
                }  
            }  
        }  
          
        for(int i=0;i<n;i++){  
            A[i][i]=-1;  
            for(int j=0;j<edge[i].size();j++){//j->i  
                int v=edge[i][j];  
                if(i==v)continue;  
                A[i][v]=1.0/d[v];  
            }  
        }  
        for(int i=0;i<=n;i++)  
            A[n-1][i]=1;  
          
        int cnt=1;  
        for(int i=0;i<n-1;i++){//枚举点  
            if(g[n-1][i]==0){//连边  
                for(int j=0;j<n;j++){  
                    if(g[n-1][j]){//修改n-1指向的所有点  
                        A[j][n+cnt]=1.0/(d[n-1]+1);  
                    }  
                    else A[j][n+cnt]=0;  
                }  
                A[i][n+cnt]=1.0/(d[n-1]+1);  
                A[n-1][n+cnt]=1;  
                add[cnt]=i;  
                cnt++;  
            }  
        }  
        if(!Gauss(n,n+cnt)){  
            printf("INF\n");  
        }  
        else{  
            int max_cnt=-1;  
            double mmax=A[n-1][n]/A[n-1][n-1];  
            for(int i=1;i<cnt;i++){  
                if(A[n-1][n]/A[n-1][n+i]>mmax){  
                    max_cnt=add[i];  
                    mmax=A[n-1][n]/A[n-1][n+i];  
                }  
            }  
            printf("%d %d\n",1,max_cnt);  
        }  
    }  
    return 0;  
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值