码迷,mamicode.com
首页 > 其他好文 > 详细

uva 10859 Placing Lampposts,树形dp

时间:2015-05-28 09:37:26      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:uva 10859   placing lampposts   树形dp   

// uva 10859 Placing Lampposts
// 树形dp
//
// 题目的意思是一个无向无环图中,有一些顶点和一些边
// 要在顶点上放置灯笼(灯笼可以照亮与它相邻接的点),
// 使得所有的边都能被灯笼照亮,其中可能有一些边被两个灯笼
// 照亮,则要求使得所有边都被灯笼照亮所需灯笼的最小值,
// 并且,此时边同时被两个灯笼照亮的数目应尽可能的多
//
// 思路是
// d[i][0]表示在节点i不放置灯笼所需的灯笼的最小值
// d[i][1]表示在节点i放置灯笼所需的灯笼的最小值
//
//	先说明一下一下j表示i的子节点
//
//
// 则状态转移方程为
// d[i][0] += d[j][1];(这条路必须要被照亮)
// d[i][1] += max(d[j][1],d[j][0])
//
// 再定义一个f
// f[i][0]表示节点i放置灯笼边同时被两个灯笼照亮的总数最大值
// f[i][1]表示节点i放置灯笼边同时被两个灯笼照亮的总数最大值
// 
// 则状态转移可能有点复杂
// 如下所示:
// 首先f数组肯定要根据d数组来递推
//
// f[i][0] += f[j][1] (没得选,i到j必须被照亮)
//
// f[i][1] 应该首先根据d[j][0] 和 d[j][1] 来
// 如果后面的两者不相等,则取较小的第二维记作mk(保证总的灯笼最小)
// 此时f[i][1] += f[j][mk] + mk ? 1 : 0; (如果mk==1则i到j的边被两个灯笼
// 照亮,即加一)
//
// 如果d[j][0] == d[j][1];
//
// 则此时f[i][1] += max(f[j][0],f[j][1] + 1)(在i放灯笼的情况下,j放不放灯笼
// 所需的灯笼的总数都是一样的,那么就看j放灯笼的 f[j][1]+1 大
// 还是不放灯笼的f[j][0]大)
//
// 至此,这道题目算是思路很清楚了。另外就是要注意图可能是不连通的
//
// 下面说说这题给我带来的感受。以及自身的一丝变化。
//
// 这一题是我真真正正自己想出来,并努力自己做出来的题目。看到mw给我看的一组
// ACM前辈的问答:为什么当初我们是一个水平,但是后来你进了final,我却没有
// 回答是:我在有了一定的基础之后就不看解题报告了。这句话给我一直很大的冲击
// 如果是刚入门的时候,你看看题解,没人会说你什么,因为都是菜鸟,看看题解,
// 入门会快一些,也会多一些经验,在入了门以后,再看题解,也没人会说什么,自
// 己会清楚自己的状态,如果你认为看题解对你有帮助,那就看呗,如果不是为自己
// 毫无意义的虚荣心的话。
//
// 虽然我以前经常在无助的时候看题解,也并不明白为什么是这样,所以我反复的提
// 交,反复的看,反复的提交,在自己不明白的地方就加上自己理解的代码再提交。
// 虽然当时真的感觉自己吃透这一题了,但是在过了不久之后再看到这一题的时候还
// 是感觉像是新的题目一样。如果你大多数都是看题解的话,建议你把以前的题目在
// 做一遍,如果没有我这样的感受,我只能在这里膜拜一发各位巨巨。但对于我来说
// 就是这样。
//
// 这道题目其实训练指南上有详细的解题指导,我也看了,但是完全看不懂在讲什么
// 在自己卡了两天,wrong answer 了好久之后,这段时间我真的是忍不住差点跟着
// 书上的思路敲一遍算了的想法出现,但最终我还是忍住了,一遍一遍的调试,最后
// 的结果还是挺让人高兴的。那种accept的感受不是简单的过了的感受,而是自己的
// 成果最终是有回报的。在此,我要感谢mw,是他点醒了我,会求一个值,就会求
// 第二个值。猛然醒悟。
// 虽然这题仔细想来并不是很难,但这是
// 我感受到了自己的喜悦,不多说,继续努力,付出总会有回报。fighting
//

#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <vector>
#define ceil(a,b) (((a)+(b)-1)/(b))
#define endl '\n'
#define gcd __gcd
#define highBit(x) (1ULL<<(63-__builtin_clzll(x)))
#define popCount __builtin_popcountll
typedef long long ll;
using namespace std;
const int MOD = 1000000007;
const long double PI = acos(-1.L);

template<class T> inline T lcm(const T& a, const T& b) { return a/gcd(a, b)*b; }
template<class T> inline T lowBit(const T& x) { return x&-x; }
template<class T> inline T maximize(T& a, const T& b) { return a=a<b?b:a; }
template<class T> inline T minimize(T& a, const T& b) { return a=a<b?a:b; }

const int maxn = 1008;
int head[maxn];
struct node{
	int to;
	int next;
}edges[maxn*2];
int num;

int n,m;
int f[maxn][2];
int d[maxn][2];
bool vis[maxn];
void add_edges(int u,int v){
	edges[num].to = v;
	edges[num].next = head[u];
	head[u] = num++;
}

void init(){
	memset(f,0,sizeof(f));
	memset(head,-1,sizeof(head));
	memset(vis,0,sizeof(vis));
	num=0;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add_edges(u,v);
		add_edges(v,u);
	}
}

void dfs(int u,int fa){
	d[u][0] = 0;
	d[u][1] = 1;
	vis[u] = true;
	for (int i=head[u];i!=-1;i=edges[i].next){
		int v = edges[i].to;
		if (!vis[v]){
			dfs(v,u);
			d[u][0] += d[v][1];
			int mk = -1;
			if (d[v][0] < d[v][1]){
				mk = 0;
			}else {
				mk = 1;
			}
			d[u][1] += d[v][mk];
			int temp = 0;
			temp = f[v][mk] + (mk?1:0);
			if (d[v][1]==d[v][0])
				temp =  max(temp,max(f[v][1]+1,f[v][0]));
			f[u][1] += temp;
			//d[u][1] += min(d[v][0],d[v][1]);
			f[u][0] += f[v][1];
		}
	}
}

void print(){
	for (int i=0;i<n;i++){
		printf("%d %d\n",f[i][0],f[i][1]);
	}
}

void solve(){
	int sum = 0;
	int mx = 0;
	for (int i=0;i<n;i++)
		if (!vis[i]){
			dfs(i,-1);
			int mk=0;
			if (d[i][0]<d[i][1])
				mk = 0;
			else 
				mk = 1;
			if (d[i][0] == d[i][1])
				mk = f[i][0] > f[i][1] ? 0 : 1 ;
			
			sum += d[i][mk];
			mx += f[i][mk];
		}
	//print();
	//cout << mk << endl;
	//mn = min(d[0][0],d[0][1]);
	printf("%d %d %d\n",sum,mx,m-mx);
}

int main() {
	int t;
	//freopen("G:\\Code\\1.txt","r",stdin);
	scanf("%d",&t);
	while(t--){
		init();
		solve();
	}
	return 0;
}

uva 10859 Placing Lampposts,树形dp

标签:uva 10859   placing lampposts   树形dp   

原文地址:http://blog.csdn.net/timelimite/article/details/46063273

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!