[牛客21295]奇异图(构造+贪心+Flyod)

题目链接:

https://ac.nowcoder.com/acm/problem/21295?&headNav=acm

题目描述

有一张n个点的无向完全图,给每一条边规定一个方向后可以得到一个新图
我们称这样的图为奇异图
现在只知道奇异图每个点的出度
你需要计算有多少点对(u, v) u可以到达v,特殊的,每个点自己都可以到达自己
保证答案唯一

输入描述:

第一行输入一个整数n (1 ≤ n ≤ 100)
第二行输入n个整数a[i]

输出描述:

输出一个整数

 

题解:

%%%skyh图论小皇子

%%%B哥图论太上皇

首先看到这道题一定会想到不会是计数,那就是图论,又因为数据保证答案唯一,所以大概可以猜出是建图跑最短路

建图很神:每次找出当前出度最小的点,把其入度与以后的出度大的点挨个匹配,出度同理,这样便可以防止出现下面的情况:

错解是直接找能建边就建边,但是3这个点本应该是->2,但是它在2的时候被2改变了方向变成了2->3,这导致了2无法满足入度需求,

反观正解的思路:用最大的出度向当前点连边,便可以解决这种情况:它最大可能的保留了可以连出/入的点的个数,以便后面成功建图

所以其正确性是可以证明的。


 

最后附上代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 using namespace std;
 5 int ans,n,e[105][105];
 6 struct node{int id,in,out;}a[105];
 7 bool comp1(node l,node r){return l.out<r.out;}
 8 bool comp2(node l,node r){return l.in>r.in;}
 9 signed main()
10 {
11         //freopen("1.in","r",stdin);
12         scanf("%d",&n);
13         for(int i=1;i<=n;i++) a[i].id=i,e[i][i]=1,scanf("%d",&a[i].out),a[i].in=n-a[i].out-1;
14         for(int i=1;i<n;i++)
15         {
16                 sort(a+i,a+n+1,comp2);
17                 for(int j=i+1;j<=n;j++)
18                 {
19                         if(!a[i].out) break;
20                         a[i].out--,a[j].in--;
21                         e[a[i].id][a[j].id]=1;
22                 }
23                 sort(a+i,a+n+1,comp1);
24                 for(int j=n;j>=i+1;j--)
25                 {
26                         if(!a[i].in) break;
27                         if(e[a[i].id][a[j].id]) continue;
28                         a[i].in--,a[j].out--;
29                         e[a[j].id][a[i].id]=1;
30                 }
31         }
32         for(int k=1;k<=n;k++)
33         {
34                 for(int i=1;i<=n;i++)
35                 {
36                         for(int j=1;j<=n;j++)
37                         {
38                                 e[i][j]|=e[i][k]&e[k][j];
39                         }
40                 }
41         }
42         for(int i=1;i<=n;i++)
43         {
44                 for(int j=1;j<=n;j++)
45                 {
46                         ans+=e[i][j];
47                 }
48         }
49         printf("%d",ans);
50         return 0;
51 }
View Code

 

 

posted @ 2019-11-11 21:02  ATHOSD  阅读(315)  评论(2编辑  收藏  举报