题意就是设置最少的哨兵,能够看到所有的路。
二分图也能解决,即二分图最小点覆盖 用vector超内存了,
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define MAXN 1600
#define MAXE 300000
struct Edge
{
int v; //
int next;
}edge[MAXE];
int head[MAXN]; // 每个点临接的边
int cnt ; // 边的条数
int n ; // 点的个数
int path[MAXN];
bool used[MAXN];
void add(int u,int v)
{
edge[cnt].v = v;
edge[cnt].next = head[u];
head[u] = cnt++;
edge[cnt].v = u;
edge[cnt].next = head[v];
head[v] = cnt++;
}
bool dfs(int u)
{
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(!used[v])
{
used[v] = true;
if(path[v] == -1 || dfs(path[v]))
{
path[v] = u;
return true;
}
}
}
return false;
}
int match()
{
int res = 0;
memset(path,-1,sizeof(path));
for(int u = 0; u < n; u++)
{
memset(used,0,sizeof(used));
if(dfs(u))
res++;
}
return res;
}
int main()
{
//freopen("Input.txt","r",stdin);
while(scanf("%d",&n) != EOF)
{
memset(edge,0,sizeof(edge));
memset(head,-1,sizeof(head));
cnt = 0;
for(int i = 0; i < n; i++)
{
int a,b,c;
scanf("%d:(%d)",&a,&b);
while(b--)
{
scanf("%d",&c);
add(a,c);
}
}
cout<<match()/2<<endl;
}
return 0;
}
用树形dp求解即,每个点都有设哨兵和不设哨兵。dp1为设置哨兵,dp2为不设置哨兵。
则 dp1【s】 + =min(dp1【x】,dp2【x】);//s为父节点,x为子节点。
dp2【s】 + = sum{ dp1【x】}; 父节点不设置哨兵,则其子节点都要设置哨兵。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
vector<int>V[1500];
int vis[1500];
int dp1[1500],dp2[1500];//设和不设
void init()
{
for(int i=0;i<1500;i++)
{
V[i].clear();
dp1[i]=1;
dp2[i]=0;
}
memset(vis,0,sizeof(vis));
}
void dfs(int s)
{
vis[s]=1;
for(int i=0;i<(int)V[s].size();i++)
{
int x=V[s][i];
if(!vis[x])
{
dfs(x);
dp2[s]+=dp1[x];
dp1[s]+=min(dp1[x],dp2[x]);
}
}
}
int main()
{
//freopen("Input.txt","r",stdin);
int n,i,j,k,x;
while(~scanf("%d",&n))
{
init();
for(i=1;i<=n;i++)
{
scanf("%d:(%d)",&j,&k);
while(k--)
{
scanf("%d",&x);
V[j].push_back(x);
V[x].push_back(j);
}
}
dfs(0);
printf("%d\n",min(dp1[0],dp2[0]));
}
return 0;
}