SGU 219 Synchrograph tarjian找环,理解题意,图论 难度:3

http://acm.sgu.ru/problem.php?contest=0&problem=219

题目大意:

如果指向某个点的边权全都为正数,那么这个点就是可点燃的,点燃操作把入弧权值-1,出弧权值都+1,

如果在某种点燃序列之后还可以再点燃一些点使得这个点还可以点燃,那么这个点在这种点燃序列之后存活

如果在任何点燃序列之后都还可以再点燃一些点使得这个点还可以点燃,那么这个点可存活

现在求所有点是否可存活

思路:

考虑不可存活的点:对于某个状态,对于不可存活的点,要想使得没有序列可以使它被点燃,那么有边指向它的点里一定有不可存活的点,且这条边权值为0,

如果有一个边权值都为0的环,那么在这条环上,由于权值都为0,所以这个环上的都是不可存活的点.

所以:先通过求边权值都为0的环确定一些初始点,由这些不可存活点出发到达的点,都在某个序列下因为这些不可存活点不能提供权值而不能存活

注意:

1. 有自环

2. tarjian找环需要注意更新dfn值的点在stack内,否则对于我写的形式

会有这种情况不正确

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
#include  <cstdio>
#include <stack>
#include <cstring>
using namespace std;
const int maxn=1e3+3;
const int maxm=5e4+4;
int n,m;
 
int first[maxn],head[maxn];
struct edge{
        int t,nxt;
}e[maxm],g[maxm];
 
int low[maxn],dp[maxn],depth;
int alive[maxn];
bool in[maxn];
 
void addedge(int f,int t,int c,int ind){
        if(c==0){
                g[ind].nxt=head[f];
                g[ind].t=t;
                head[f]=ind;
        }
        e[ind].nxt=first[f];
        e[ind].t=t;
        first[f]=ind;
}
 
stack<int> st;
void tarjian(int s){
        low[s]=dp[s]=++depth;
        in[s]=true;st.push(s);
        for(int p=head[s];p!=-1;p=g[p].nxt){
                int t=g[p].t;
                if(t==s){
                        alive[s]=0;
                }
                if(dp[t]==0){
                        tarjian(t);
                        low[s]=min(low[s],low[t]);
                }
                else if(in[t]){//ATTHENTION:
                        low[s]=min(low[s],dp[t]);
                }
        }
 
        bool single=true;
        if(low[s]==dp[s]){
                while(st.top()!=s){
                        single=false;
                        alive[st.top()]=0;
                         
                        in[st.top()]=false;st.pop();
                }
                if(!single){
                        alive[st.top()]=0;
                }
                in[st.top()]=false;st.pop();
        }
}
 
void dfs(int s){
        for(int p=first[s];p!=-1;p=e[p].nxt){
                int t=e[p].t;
                if(alive[t]==1){
                        alive[t]=0;
                        dfs(t);
                }
        }
 
}
 
int main(){
        scanf("%d%d",&n,&m);
        memset(first,-1,sizeof(first));
        memset(head,-1,sizeof(head));
        fill(alive,alive+n+1,1);
        for(int i=0;i<m;i++){
                int f,t,c;
                scanf("%d%d%d",&f,&t,&c);
                addedge(f,t,c,i);
        }
 
        for(int i=1;i<=n;i++){
                if(dp[i]==0){
                        tarjian(i);
                }
        }
 
        for(int i=1;i<=n;i++){
                if(alive[i]==0){
                        dfs(i);
                }
        }
 
        for(int i=1;i<=n;i++){
                printf("%d\n",alive[i]);
        }
 
        return 0;
}

  

 

posted @   雪溯  阅读(320)  评论(0编辑  收藏  举报
编辑推荐:
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Linux系统下SQL Server数据库镜像配置全流程详解
· 现代计算机视觉入门之:什么是视频
· 你所不知道的 C/C++ 宏知识
阅读排行:
· 【译】我们最喜欢的2024年的 Visual Studio 新功能
· 个人数据保全计划:从印象笔记迁移到joplin
· Vue3.5常用特性整理
· 重拾 SSH:从基础到安全加固
· 并发编程 - 线程同步(一)
点击右上角即可分享
微信分享提示