10859 Placing Lampposts UVA

20 篇文章 0 订阅
19 篇文章 0 订阅

Input: Standard In
Output: Standard Out

Next Generation Contest 1 

Time Limit: 2 seconds

Problem D
Placing Lampposts

As a part of the mission �Beautification of Dhaka City�, the government 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 the requirement, the government has decided to buy the minimum number of lampposts required to light the whole city.

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

The �Dhaka City Corporation� has given you the road map of Dhaka city. You are hired to find the minimum number of lampposts that will be required to light the whole city. These lampposts can then be placed on the required junctions to provide the service. There could be many combinations of placing these lampposts that will cover all the roads. In that case, you have to place them in such a way that the number of roads receiving light from two lampposts is maximized.

Input

There will be several cases in the input file. The first line of input will contain an integer T(T<=30) that will determine the number of test cases. Each case will start with two integers N(N<=1000) and M( M<N) that will indicate the number of junctions and roads respectively. The junctions are numbered from 0 to N-1. Each of the next M lines will contain two integersa and b, which implies there is a road from junction a to b,
( 0<= a,b < N ) and a != b. There is a blank line separating two consecutive input sets.

Output

For each line of input, there will be one line of output. Each output 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 receiving lights from two lampposts and the third integer will be the number of roads that are 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

原理见p71

被两盏灯照亮的边数b尽量大 <==> 被一盏灯照亮的边数c尽量小

a为灯的数目

设x=Ma+c    M足够大则题意即求x的最小值!!!!!!!(关键)

d(i,j)表示i的父亲节点j是否放灯(1为放0为未放),以i为根的树x的最小值。。。。。

那么对于个子树只有两种可能在i放与不放灯

代码如下:

#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <vector>
using namespace std;
int vis[1010][2];
int d[1010][2];
vector<int> adj[1010];
int dp(int i,int j,int f)//f是i的父亲节点f=-1表示无父亲节点
{
    if(vis[i][j])
    return d[i][j];
    vis[i][j] = 1;
    int& ans = d[i][j];
    //在i处放灯。。。因为放灯总是合法决策
    ans = 2000;//x = Ma + c于是放一盏灯x增大2000
    for(int k = 0;k<adj[i].size();++k)
      if(adj[i][k]!=f)//不是父亲节点那么是子节点
         ans += dp(adj[i][k],1,i);
     if(!j && f>=0)//如果i不是根并且父亲节点没放灯则ans++(因为j->i也是一条只有一盏等的边)
      ++ans;


      //在i处不放灯
    if(j || f<0)//i是根或者i的父亲节点放灯(只有这种情况下才允许i处不放灯)
    {
        int sum = 0;
        for(int k = 0;k<adj[i].size();++k)
              if(adj[i][k]!=f)//不是父亲节点那么是子节点
               sum += dp(adj[i][k],0,i);
         if(f>=0)//如果i不是根那么sum++(因为j->i也是一条只有一盏等的边)
         sum++;
         ans = min(ans,sum);//取两种情况的最小值
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    for(int i = 0;i<t;++i)
    {
        int m,n;
        scanf("%d%d",&n,&m);
        for(int j = 0;j<n;++j)
        adj[j].clear();
        for(int j = 0;j<m;++j)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            adj[a].push_back(b);
            adj[b].push_back(a);
        }
        memset(vis,0,sizeof(vis));
        int ans =0 ;
        for(int i = 0;i<n;++i)//遍历所有的节点
        {
            if(!vis[i][0])
             ans += dp(i,0,-1);
        }
        printf("%d %d %d\n",ans/2000,m-ans%2000,ans%2000);
    }

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值