gfoj树形dp 有线电视网

题目:http://www.gdfzoj.com/oj/contest/271/problems/4

有点小长~

某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。

从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和。

现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号。

写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多。

 

典型树形dp

没啥好说的

注意:用vector边权应转为点权(按习惯来)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

struct node
{
	int y,wei;
};

const int maxS=3000;
int n,m;
int mo[maxS+5][maxS+5];//记录连接树叶的边 
int vis[maxS+5],f[maxS+5][maxS+5],num[maxS+5];
vector <node> edge[maxS+5];

void dfs1(int x)
{
	int i,t=0;
	node n1;
	
	for (i=0;i<edge[x].size();i++)
	{
		n1=edge[x][i];
		if (vis[n1.y]==1)
			continue;
		vis[n1.y]=1;	t=1;
		dfs1(n1.y);
		vis[n1.y]=0;
		num[x]+=num[n1.y];
	}
	if (t==0)
		num[x]=1;
}

void dfs(int x,int wei)
{
	int i,j,k,t=0;
	node n1;
	
	f[x][0]=0;
	for (i=0;i<edge[x].size();i++)
	{
		n1=edge[x][i];
		if (vis[n1.y]==1)
			continue;
		vis[n1.y]=1;	t=1;
		dfs(n1.y,n1.wei);
		vis[n1.y]=0;
		for (j=num[x];j>=1;j--)
		{
			for (k=0;k<=min(j,num[n1.y]);k++)
			{
				f[x][j]=min(f[x][j],f[x][j-k]+f[n1.y][k]);
			}
		}
	}
	if (t==0)
		f[x][1]=wei;
	else
		for (i=1;i<=num[x];i++)
			f[x][i]+=wei;
}

int main()
{
	int i,j,k,j1,x;
	node n1;
	
	freopen("a.txt","r",stdin);
	scanf("%d%d",&n,&m);
	
	memset(mo,0,sizeof(mo));
	for (i=1;i<=n-m;i++)
	{
		scanf("%d",&k);
		for (j=0;j<k;j++)
		{
			scanf("%d",&j1);
			scanf("%d",&n1.wei);
			n1.y=j1;
			if (j1>n-m)
				mo[i][j1]=edge[i].size();
			edge[i].push_back(n1);
			n1.y=i;
			edge[j1].push_back(n1);
		}
	}
	for (i=n-m+1;i<=n;i++)
	{
		scanf("%d",&x);
		j1=edge[i][0].y;
		edge[i][0].wei-=x;
		edge[j1][mo[j1][i]].wei-=x;
	}
	memset(vis,0,sizeof(vis));
	memset(f,0x3f,sizeof(f));
	memset(num,0,sizeof(num));
	vis[1]=1;
	dfs1(1);
	dfs(1,0);
	for (i=num[1];i>=0;i--)
	{
		if (f[1][i]<=0)
		{
			printf("%d\n",i);
			break;
		}
	}
	
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值