Tree
Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 2564 | Accepted: 859 |
Description
Consider a tree with N vertices, numbered from 1 to N. Add, if it is possible, a minimum number of edges thus every vertex belongs to exactly one cycle.
Input
The input has the following structure:
N
x(1) y(1)
x(2) y(2)
...
x(N-1) y(n-1)
N (3 <= N <=100) is the number of vertices. x(i) and y(i) (x(i), y(i) are integers, 1 <= x(i), y(i) <= N) represent the two vertices connected by the i-th edge.
N
x(1) y(1)
x(2) y(2)
...
x(N-1) y(n-1)
N (3 <= N <=100) is the number of vertices. x(i) and y(i) (x(i), y(i) are integers, 1 <= x(i), y(i) <= N) represent the two vertices connected by the i-th edge.
Output
The output will contain the value -1 if the problem doesn't have a solution, otherwise an integer, representing the number of added edges.
Sample Input
7 1 2 1 3 3 5 3 4 5 6 5 7
Sample Output
2
Source
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INF 100
#define MAXN 110
#define MAXE 220
struct LEdge{
int ed, next;
}edge[MAXE];
int head[MAXN], nEdge;
void init(){
nEdge = 0;
memset(head, 0xff, sizeof(head));
}
void addEdge(int i, int j){
edge[nEdge].ed = j;
edge[nEdge].next = head[i];
head[i] = nEdge++;
}
int f[MAXN][3];
int imin(int a, int b){
if (a < 0) return b;
if (b < 0) return a;
return a < b ? a : b;
}
int dfs(int pre, int cur){
int i, j, k, p, q, sum;
sum = 0;
for (i = head[cur]; i != -1; i = edge[i].next){
k = edge[i].ed;
if (k == pre) continue;
if (!dfs(cur, k)) return 0;
sum += f[k][0];
}
f[cur][0] = f[cur][1] = f[cur][2] = INF;
f[cur][1] = sum;
for (i = head[cur]; i != -1; i = edge[i].next){
p = edge[i].ed;
if (p == pre) continue;
f[cur][0] = imin(f[cur][0], f[p][2] - f[p][0] + sum + 1);
f[cur][2] = imin(f[cur][2], f[p][2] - f[p][0] + sum);
f[cur][2] = imin(f[cur][2], f[p][1] - f[p][0] + sum);
for (j = edge[i].next; j != -1; j = edge[j].next){
q = edge[j].ed;
if (q == pre) continue;
f[cur][0] = imin(f[cur][0], f[p][1] - f[p][0] + f[q][1] - f[q][0] + sum + 1);
f[cur][0] = imin(f[cur][0], f[p][2] - f[p][0] + f[q][1] - f[q][0] + sum + 1);
f[cur][0] = imin(f[cur][0], f[p][1] - f[p][0] + f[q][2] - f[q][0] + sum + 1);
f[cur][0] = imin(f[cur][0], f[p][2] - f[p][0] + f[q][2] - f[q][0] + sum + 1);
}
}
// printf("cur = %d, f[0] = %d, f[1] = %d, f[2] = %d, t = %d, p = %d, q = %d, r = %d\n", cur, f[cur][0], f[cur][1], f[cur][2], t, p, q, r);
if (f[cur][0] >= INF && f[cur][1] >= INF && f[cur][2] >= INF)
return 0;
return 1;
}
int main(){
int i, j, k, n;
while(scanf("%d", &n) != EOF){
init();
for (k = 1; k < n; k++){
scanf("%d%d", &i, &j);
addEdge(i, j);
addEdge(j, i);
}
if (!dfs(0, 1) || f[1][0] >= INF) f[1][0] = -1;
printf("%d\n", f[1][0]);
}
return 0;
}
/*
f[i][0] i及其以下已成环
f[i][1] 仅i没成环
f[i][2] i带着一个长至少为2的链
f[i][0] = min(
f[p][1] + f[q][1] + sum(f[其他][0]) + 1,
f[p][2] + f[q][1] + sum(f[其他][0]) + 1,
f[p][1] + f[q][2] + sum(f[其他][0]) + 1,
f[p][2] + f[q][2] + sum(f[其他][0]) + 1,
f[p][2] + sum(f[其他][0]) + 1)
f[i][1] = sum(f[其他][0])
f[i][2] = min(
f[p][2] + sum(f[其他][0]),
f[p][1] + sum(f[其他][0]))
开始无效值是-1,虽然做了好多好多特判
例如,有的子树本身无法全部成环,这样的点如果有一个,
可以通过和当前点组成环,或者和其他链组成环,或者作为当前点的链
如果有两个,则必须把他俩连一块
如果多于两个,说明无解
但是都WA掉了
后来看了网上的,没那么多特判,枚举起来也特暴力
初值设的INF,于是改成比较暴力的二重循环,而不是一重去找,
写的简单了,也就过了
经验: 尽量简洁,卡住了就释放些暴力
*/