(转)E - Strategic Game (HDU - 1054 )(最小顶点覆盖)(匈牙利算法模板)(树形DP)

#include<bits/stdc++.h>
using namespace std;
const int N=1500+5;

vector G[N];
int visit[N];
int match[N];
int n;
int Find(int u)//匈牙利算法
{
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!visit[v])
{
visit[v]=1;
if(match[v]==-1 ||Find(match[v]))
{
match[v]=u;
return 1;
}
}
}
return 0;
}
int main()
{
//std::ios::sync_with_stdio(false);
//std::cin.tie(0);
int m,k;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
{
scanf("%d:(%d)",&m,&k);
for(int j=0;j<k;j++)
{
int a;
scanf("%d",&a);
G[a].push_back(m);
G[m].push_back(a);
}
}
memset(match,-1,sizeof(match));
int ans=0;
for(int i=0;i<n;i++)
{
memset(visit,0,sizeof(visit));
if(Find(i))
ans++;
}
printf("%d\n",ans/2);
for(int i=0;i<N;i++)
G[i].clear();
}
}

匈牙利算法模板

有个讲解不错的网址 http://blog.csdn.net/dark_scope/article/details/8880547/

bool find(int x){
int i,j;
for (j=1;j<=m;j++){ //扫描每个妹子
if (line[x][j]==true && used[j]==false)
//如果有暧昧并且还没有标记过(这里标记的意思是这次查找曾试图改变过该妹子的归属问题,但是没有成功,所以就不用瞎费工夫了)
{
used[j]=1;
if (girl[j]==0 || find(girl[j])) {
//名花无主或者能腾出个位置来,这里使用递归
girl[j]=x;
return true;
}
}
}
return false;
}
for (i=1;i<=n;i++)
{
memset(used,0,sizeof(used)); //这个在每一步中清空
if find(i) all+=1;
}

另外也可以用树形DP来做,

【状态】:

dp[i][0] 为以 i 为根节点,并且该节点不放,所需要的最少的点数

dp[i][1] 为以 i 为根节点,并且该节点放,所需要的最少的点数

【转移方程】:

dp[i][0]=sum(dp[son[i][j]][1]) 该点不放的话,那么它的儿子节点必须都放,这样之间的边才可以被覆盖

dp[i][1]=sum(min(dp[son[i][j]][0],dp[son[i][j]][1])) 该点放的话,那么它的儿子节点就有两种决策,一种是放,一种是不放,取 min 就行了

#include<bits/stdc++.h>
using namespace std;
const int N=1505;

int dp[N][2],f[N];
int son[N][N],Size[N];
int n;

int dfs(int pos ,int val)
{
if(dp[pos][val]!=INT_MIN)
return dp[pos][val];
int sum= val;
for(int i=0; i<Size[pos]; i++)
{
if(val==1)
sum+= min( dfs(son[pos][i],0) , dfs(son[pos][i],1) );
else
sum+= dfs(son[pos][i],1) ;
}
return dp[pos][val]=sum;
}
int main()
{
//std::ios::sync_with_stdio(false);
//std::cin.tie(0);
int x,y,z;
while(~scanf("%d",&n))
{
for(int i=0; i<n; i++)
{
f[i]=i;
dp[i][0]=dp[i][1]=INT_MIN;
}
int k=n;
while(k–)
{
scanf("%d:(%d)",&x,&y);
Size[x]=y;
for(int i=0; i<y; i++)
{
scanf("%d",&z);
son[x][i]=z;
f[z]=x;
}
}
int ans;
for(int i=0; i<n; i++)
{
if(f[i]==i)
{
ans=min( dfs(i,0) , dfs(i,1) );
break;
}
}
printf("%d\n",ans);
}
}


原文链接:https://blog.csdn.net/Draven__/article/details/76974092

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值