UVA - 10859 Placing Lampposts (蛮好的一道题目)

本文介绍了一种解决特定图论问题的方法,该问题要求在确保所有边被照亮的前提下,尽可能减少所需灯的数量,并最大化被两盏灯同时照亮的边数。通过动态规划策略实现了最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给你一个n个点m条边的无向无环图,在尽量少的结点放灯,使得所有边都被照亮,每盏灯将照亮以它为一个端点的所有的边,在灯的数量小的前提下,被两盏灯同时照亮的边数应尽量大

思路:大白的题目,本题的优化目标有两个,这是这道题母的亮点:放置的灯数a应尽量少,被两盏灯同时照亮的边数b应尽量大,为了同一起见,我们把后者替换为:恰好被一盏灯同时照亮的边数c应尽量小,然后改用x=Ma+c作为最小化的目标,其中M是一个很大的正整数,当x取到最小值时,x/M的整数部分就是放置的灯数的最小值:x%M就是恰好被一盏灯照亮的边数的最小值。

决策一:节点i不放灯,必须j=1或者i是根节点时才允许作这个决策,如果i不是根的话,还要加上1

决策二:节点i放灯,如果j=0且i不是根节点,那么同样还要加上1 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN = 1010;

vector<int> adj[1010];
int vis[MAXN][2],d[MAXN][2],n,m;

int dp(int i,int j,int f){
    if (vis[i][j])
        return d[i][j];
    vis[i][j] = 1;
    int &ans = d[i][j];
    ans = 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)
        ans++;
    if (j || f < 0){
        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)
            sum++;
        ans = min(ans,sum);
    }
    return ans;
}

int main(){
    int t,a,b;
    scanf("%d",&t);
    while (t--){
        scanf("%d%d",&n,&m);
        for (int i = 0; i < n; i++)
            adj[i].clear();
        for (int i = 0; i < m; i++){
            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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值