P2860 [USACO06JAN]冗余路径Redundant Paths+tarjan算法+构建全环图

题目大意:
任意两个点之间至少有两条边相连,且两条边没有重合之处。
例如:
1->2->3->4;
1->2->5->4;
不满足要求;两条路径中都有1->2;
解题思路:
环中的任意两点有两条满足要求的路径;
在所给图上添加边,使得图中任意一个点都在某个环中;
算法:
tarjan算法缩点+无向图中统计入度和出度同时为1的点的个数c+处理c;
**若c是偶数,则ans=c/2;若c是奇数,则ans=c/2+1;
处理c的方法,可以画个图看一下;

《就本题而言,Tarjan算法不受重边的影响》

代码中有许多细节需要注意:
1,因为是无向图且有环,对两条边同时进行标记,这就要使得控制e的cnt初始值为-12,如果要使用两次e数组和head数组,head数组要初始化,控制e数组的cnt要初始化-1,和第一次
相同;
#include<map>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int num=5010;
/*------------------*/
struct node{
    int u,v,next;
    bool flag;
}e[num<<2],e2[num<<2];

int head[num],cnt,cnt1;
int ip[num],op[num];
/*------------------*/
int dfn[num],low[num],ind,stack[num],t,cnt2,f[num];
bool vis[num];
/*------------------*/
/*------------------*/
/*------------------*/
int n,m;
void int_i(void)
{
    cnt=-1;
    memset(head,-1,sizeof(head));
    ind=0;
    t=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,-1,sizeof(low));
    memset(vis,0,sizeof(vis));
    memset(ip,0,sizeof(ip));
    memset(op,0,sizeof(op));
    cnt2=0;
    return ;
}
void addedge(int u,int v)
{
    e[++cnt].u=u;
    e[cnt].v=v;
    e[cnt].flag=false;
    e[cnt].next=head[u];
    head[u]=cnt;
    return ;
}
void addedge2(int u,int v)
{
    e2[++cnt].u=u;
    e2[cnt].v=v; 
    e2[cnt].next=head[u];
    head[u]=cnt;
    return ;
}
void tarjan(int u)
{
    int v;
    dfn[u]=low[u]=++ind;
    stack[++t]=u;
    vis[u]=true;
    for(int i=head[u];i!=-1;i=e[i].next)
    {
       // printf("u===%d\n",u);
        if(e[i].flag) continue;
        e[i].flag=e[i^1].flag=true;
        v=e[i].v;
      //  printf("v==%d\n",v);
       // getchar();
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }

    if(dfn[u]==low[u])
    {
        cnt2++;
        do{
            v=stack[t--];
            vis[v]=false;
            f[v]=cnt2;
            //w[cnt2]++;
            //printf("%d,%d\n",cnt2,v);
        }while(v!=u);
    }
    return ;
}
int main()
{
    int u,v;
    scanf("%d%d",&n,&m);
    int_i();
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        addedge(u,v);
		addedge(v,u);
    }
    tarjan(1);
    cnt1=cnt;
    cnt=0;
     //如果使用e数组进行下面的操作,那么
 	//为了保证数据的正确性,cnt应该和上面的初始条件相同==-1;
 	//如果此时cnt=0;那么下面的循环,if语句里的addedge的第一个,会覆盖原始的数据
    memset(head,0,sizeof(head));
    for(int i=0;i<=cnt1;i++)
    {
        u=e[i].u;
        v=e[i].v;
        if(f[u]!=f[v])
        {
        	u=f[u];v=f[v];
            //printf("u==%d,v==%d\n",u,v);
            addedge2(u,v);
            op[u]++;ip[v]++;
        }
    }
    
    int c=0;
    for(int i=1;i<=cnt2;i++)
    {
        if(ip[i]==1&&op[i]==1){
            c++;
           // printf("i==%d\n",i);
        }
    }
    //!!!!!!!!!!!!!
    //每俩个点相连,奇数个点会剩余1个; 
    if(c%2==1) c=c/2+1;
    else c=c/2;
    printf("%d\n",c);
    return 0;
}
/*
 7 7
 1 2
 2 3
 3 4
 2 5
 4 5
 5 6
 5 7
 */ 
 /*
 //第二个测试点的数据:
 200 250
1 3
106 1
134 1
157 134
23 106
60 134
44 60
117 1
126 1
11 134
139 44
178 3
97 60
101 157
118 44
30 23
128 30
174 3
108 23
110 128
132 157
92 106
173 132
79 106
82 178
7 44
52 79
74 30
4 23
49 7
164 139
127 30
156 4
65 7
120 101
46 97
112 178
8 46
59 60
198 174
100 134
90 92
192 60
125 100
26 178
19 192
63 125
155 126
70 100
35 63
151 126
165 157
146 70
84 157
141 52
160 70
163 8
38 127
171 139
62 101
133 11
177 146
158 125
41 165
145 52
98 30
5 177
68 164
168 173
107 178
86 132
199 127
136 168
71 155
50 128
189 35
193 46
105 70
195 189
89 158
69 177
190 50
28 19
21 92
93 71
170 86
122 21
131 136
197 158
16 108
33 195
18 164
196 141
94 92
61 79
149 26
169 193
124 163
78 189
147 108
150 49
129 70
77 168
194 18
54 100
140 127
24 196
109 158
2 97
17 195
64 28
115 174
185 41
81 141
45 62
180 18
167 109
27 65
123 140
188 77
91 129
73 110
76 173
14 149
103 105
51 11
57 84
58 101
148 193
43 156
162 109
22 61
179 52
67 74
200 117
6 167
119 192
113 41
184 16
32 98
39 160
75 32
175 98
121 78
183 26
47 174
102 79
83 23
172 127
176 74
138 121
182 90
29 156
153 183
114 162
152 47
15 136
12 64
143 155
161 89
99 90
87 114
25 193
144 86
137 64
135 52
56 14
55 112
20 71
142 5
34 126
116 56
40 79
130 89
187 49
85 62
111 136
191 39
166 16
159 120
13 50
95 55
154 33
96 171
181 115
88 21
80 24
48 14
72 21
31 67
9 31
66 143
37 117
104 56
36 86
42 125
186 33
10 184
53 18
164 64
136 63
77 25
128 105
133 147
130 1
67 161
10 132
190 173
195 80
123 1
70 82
126 38
163 7
193 17
152 105
44 24
168 185
174 163
177 40
79 173
70 19
26 60
198 130
97 22
143 67
97 25
119 89
194 163
188 180
49 173
109 71
4 124
58 79
151 178
74 93
34 96
161 65
167 16
172 114
183 14
46 116
199 187
118 175
109 23
101 115
160 114
110 173
96 28
77 182
27 116
 */ 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章