uva 10859 Placing Lampposts,树形dp

来源:互联网 发布:java不换行 编辑:程序博客网 时间:2024/05/01 13:40
// 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_popcountlltypedef 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;}

0 0
原创粉丝点击