[动态规划]Placing lampposts

来源:互联网 发布:阿里云 io hang 编辑:程序博客网 时间:2024/06/05 17:01

As a part of the mission �Beautification of Dhaka City�, thegovernment has decided to replace all the old lampposts with new expensive ones.Since the new ones are quite expensive and the budget is not up to therequirement, the government has decided to buy the minimum number of lamppostsrequired to light the whole city.

Dhaka city can be modeled as an undirected graph with no cycles, multi-edges orloops. There are several roads and junctions. A lamppost can only be placed onjunctions. These lampposts can emit light in all the directions, and that means alamppost that is placed in a junction will light all the roads leading away fromit.

The �Dhaka City Corporation� has given you the road map of Dhaka city. You arehired to find the minimum number of lampposts that will be required to light thewhole city. These lampposts can then be placed on the required junctions toprovide the service. There could be many combinations of placing these lamppoststhat will cover all the roads. In that case, you have to place them insuch a way that the number of roads receiving light from two lampposts ismaximized.

Input

There will be several cases in the input file. The first lineof input will contain an integerT(T<=30) that will determine the numberof test cases. Each case will start with two integersN(N<=1000) andM( M<N) that will indicate the number of junctions and roads respectively.The junctions are numbered from0 toN-1. Each of the next Mlines will contain two integersa andb, which implies there is aroad from junctiona tob,
( 0<= a,b < N ) and a != b. There is a blank line separating twoconsecutive input sets.

Output

For each line of input, there will be one line of output. Eachoutput line will contain 3 integers, with one space separating two consecutive numbers.The first of these integers will indicate the minimum number of lampposts required to light the whole city. The second integer will be the number of roads that are receivinglights from two lampposts and the third integer will be the number of roads thatare receiving light from only one lamppost.

Sample Input

2
4 3
0 1
1 2
2 3

5 4
0 1
0 2
0 3
0 4

Sample Output

2 1 2
1 0 4

Problem Setter: Sohel Hafiz.
Special thanks to Per Austrin.


题意需要搞清楚:是照亮每条边而不是每个点。


典型的树形DP,不同之处在于有两个值a,b需要最优化。巧妙之处在于变量b是小于等于m的,且a优先级较高。因此我们可以设计一个函数,统一两个变量的表示

phi(a,b) = M*a + b

此处还需要一步转换:发现原题中要求灯数最少,而被两盏灯照亮的边数最多,不统一。于是我们把b表示为后者的补集,及只被一盏灯照亮的边(因为不存在不被照亮的情况)

动态规划父亲的决策是会影响到儿子的,为了消除后效性,我们增加一维表示父亲是否有灯,因此我们可以在当前阶段假设父亲是否放灯,提前计算代价。

方程就很明显了:

当i为叶子

d (i , 0) = M + 1

d (i , 1) = 1

当i不为根:

d (i , 0) = Σ d(k , 1) + M + 1  (i,k) ∈ E

d (i , 1) = min( Σ d(k , 1) + M , Σ d(k , 0) + 1 )   (i,k) ∈ E

当i为根

d (i , 0) = min( Σ d(k , 1) + M , Σ d(k , 0) )  (i,k) ∈ E


小心该图是一个森林,因此需要迭加所有的根的d( i , 0)


#include <cstdio>#include <cstring>bool map[1010][1010];bool used[1010];int d[1010][2];int fa[1010];int leaf[1010];const int M = 2000;int n;int min(int a,int b){if (a < b)return a;return b;}void dp(int u){    //printf("u = %d\n",u);used[u] = true;if (leaf[u] == 1){d[u][0] = M+1;d[u][1] = 1;return;}for (int v=1;v<=n;v++){        if (!map[u][v]) continue;if (used[v]) continue;        fa[v] = u;        dp(v);}int a = 0;int b = 0;for (int v=1;v<=n;v++){        if (!map[u][v]) continue;        if (fa[u]==v) continue;a += d[v][1];b += d[v][0];}a += M;if (!fa[u])d[u][0] = min(a,b);else{d[u][0] = a+1;d[u][1] = min(a,b+1);}}int main(){//freopen("lampposts.in","r",stdin);//freopen("lampposts.out","w",stdout);int T;scanf("%d",&T);while (T--){        int m;scanf("%d%d",&n,&m);memset(d,0x3f,sizeof d);memset(used,0,sizeof used);        memset(fa,0,sizeof fa);        memset(leaf,0,sizeof leaf);        memset(map,0,sizeof map);for (int i=1;i<=m;i++){int a,b;scanf("%d%d",&a,&b);            a ++; b ++;            if (!map[a][b])            {                map[b][a] = map[a][b] = true;                leaf[a] ++;                leaf[b] ++;            }}int ans = 0;for (int i=1;i<=n;i++){if (!used[i]){                leaf[i] = -100;dp(i);ans += d[i][0];}}printf("%d %d %d\n",ans/2000,m-ans%2000,ans%2000);}return 0;}