题意:
给出n个点;编号1-n,然后后给出很多对边,直到-1 ,-1位置;
然后你可以拆出一些点,并且拆出的点可以和任意点相连;
问最少拆出几个点,可以把图连成一条直线;
思路:
暴力枚举拆出哪些点,然后判断是不是可以;
如果点拆完后,剩下的图还有环,就不行;
或者还有度数大于2的也不行;
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 20;
int g[N][N],Min;
int f[N][N], vis[N],viss[N],open[N],deg[N],tdeg[N], n;
void solve(int s) {
int sum = 0;
for(int i = 0; i < n; i++) {
if((1 << i) & s) {
open[i] = 1;sum++;tdeg[i] = 0;
for(int j = 0; j < n; j++) {
f[i][j] = f[j][i] = 0;
}
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(f[i][j] == 1) {
tdeg[i]++;
}
}
}
int c = 0;
for(int i = 0; i < n; i++) {
if(open[i]) {
vis[i] = 1;
continue;
}
if(tdeg[i] > 2) {
return;
}
if(tdeg[i] == 0) {
c++;
vis[i] = 1;
continue;
}
if(!vis[i] && tdeg[i] == 1) {
c++;
vis[i] = 1;
int k = i;
int pre = -1;
bool ok = 0;
while(1) {
if(tdeg[k] > 2)
return;
ok = 0;
for(int j = 0;j < n; j++) {
if(open[j] || k == j || j == pre || f[k][j] == 0)
continue;
if(f[k][j] && vis[j]) {
return;
}
if(f[k][j] && !vis[j]) {
vis[j] = 1;
pre = k;
k = j;
ok = 1;
break;
}
}
if(!ok)
break;
}
}
}
if(sum + 1 < c) {
return;
}
for(int i = 0; i < n; i++) {
if(!vis[i])
return;
}
Min = min(sum, Min);
}
int main() {
int cas = 1;
while(scanf("%d",&n) && n) {
int a,b;
memset(g, 0,sizeof(g));
memset(deg, 0,sizeof(deg));
while(scanf("%d%d",&a,&b) && a != -1) {
g[a - 1][b - 1] = 1;
g[b - 1][a - 1] = 1;
}
Min = 0x3f3f3f3f;
for(int i = 0;i < (1 << n); i++) {
memcpy(f,g,sizeof(g));
memset(vis, 0, sizeof(vis));
memset(tdeg, 0, sizeof(tdeg));
memset(open, 0, sizeof(open));
solve(i);
}
printf("Set %d: Minimum links to open is %d\n",cas++,Min);
}
}