HDU 5811 Colosseo【竞赛图,拓扑排序】

题目链接:

http://acm.split.hdu.edu.cn/showproblem.php?pid=5811

题意:

给定竞赛图,给定若干点, 根据这些点划分成两个点集,问你每个点集构成的图中是否存在环,若均不存在环,可以将另一个点集中最多多少个点加入第一个点集仍然不会构成环。

分析:

竞赛图: 图中的任意两点间有且仅有一条有向弧连接

题中任何两个顶点之间都存在可以确定的先后关系时,所以进行拓扑排序的解是唯一的。那么对于第一问将两个点集分别求个拓扑序,再判断是否有环即可。
对于第二问,我们将第二个点集中的每个点,遍历第一个点集得到的拓扑序中找它可以放的位置,注意这个位置必须是唯一的!否则就会存在环,不予考虑。
这样我们在第二个点集原始的拓扑序基础上按照他们得到的新位置求个最长不下降子序列即可~
$O(n^2)$的复杂度活生生T了两次,后来看题解用$gets\ 200ms$过去了。
拓扑排序新姿势get,处理卡常新姿势get….

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*************************************************************************
> File Name: 5811.cpp
> Author: jiangyuzhu
> Mail: 834138558@qq.com
> Created Time: 2016/8/17 11:19:57
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 1e3 + 5, oo = 0x3f3f3f3f;
int a[2][maxn];
bool vis[maxn];
int mp[maxn][maxn];
int n, m;
struct EDGE{
int to, next;
}edge[maxn * maxn];
int head[maxn];
int tid[2][maxn];
int tot;
int in[maxn];
int dp[maxn];
int b[maxn];
void init()
{
memset(in, 0, sizeof(in));
memset(head, -1, sizeof(head));
tot = 0;
}
void addedge(int from, int to)
{
in[to]++;
edge[tot].to = to;
edge[tot].next = head[from];
head[from] = tot++;
}
bool Topology(int k)
{
int tp = 0;
queue<int>q;
for(int i = 0; i < n; i++){
if(in[i] == 0 && vis[i] != k){
q.push(i);
}
}
while(!q.empty()){
int u = q.front();q.pop();
tid[k][tp++] = u;
for(int i = head[u]; i != -1; i = edge[i].next){
in[edge[i].to]--;
if(!in[edge[i].to]) q.push(edge[i].to);
}
}
if(k) return tp == n - m;
else return tp == m;
}
char s[maxn];
int main (void)
{
while(~scanf("%d%d", &n, &m) && (n + m)){
init();
getchar();
for(int i = 0; i < n; i++){
gets(s);
for(int j = 0; j < 2 * n; j += 2){
mp[i][j / 2] = s[j] - '0';
}
vis[i] = false;
dp[i] = oo;
}
int tota = 0, totb = 0;
int x;
for(int i = 0; i < m; i++){
scanf("%d", &x);x--;
a[0][tota++] = x;
vis[x] = true;
}
for(int i = 0; i < n; i++){
if(!vis[i]){
a[1][totb++] = i;
}
}
for(int i = 0; i < n; i++){
for(int j = 0 ; j < n; j++){
if(mp[i][j] && vis[i] == vis[j]){
addedge(j, i);
}
}
}
if(!Topology(0) || !Topology(1)){
puts("NO");
continue;
}
int ans;
for(int i = 0; i < n - m; i++){
ans = -1;
for(int j = 0; j < m; j++){
if(mp[tid[0][j]][tid[1][i]]){
ans = j;
break;
}
}
if(ans == -1) ans = m;
for(int j = ans + 1; j < m; j++){
if(mp[tid[1][i]][tid[0][j]]){
ans = -1;
break;
}
}
if(ans == -1) continue;
*upper_bound(dp, dp + n - m, ans) = ans;
}
printf("YES %d\n", lower_bound(dp, dp + n - m, oo) - dp);
}
return 0;
}
文章目录
  1. 1. 题目链接:
  2. 2. 题意:
  3. 3. 分析:
  4. 4. 代码: