UVA 10859 - Placing Lampposts 树形DP、取双优值

本文介绍了一种用于城市道路照明优化的算法,旨在通过在关键交叉口安装最少数量的路灯来确保所有道路都能得到充分照明,并尽可能使更多道路受到两盏路灯的照射。

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

                          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 integers a 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

 

题意:

  一个无向图上,要去放灯,要求每条边都被照亮的最少灯数,并且1边被两盏灯照亮的边数要尽量多,输出灯数,两盏照亮的边数,一盏照亮的边数。

题解:

  首先对于每个节点,我们都有取或不取,这个DP就好了,下面是如何保证取优先值方法

取双优值方法:

      考虑要保证a最小的情况下...b最小...那么就是在状态转移过程中保证a是占主体地位的..只有当a相等时..b才发挥作用...这可以联想到两个数比较.

      首先要比最高位..当最高位不相等时..低位如何变换都不能影响到比较结果...

                 那么选取一个尽可能大但又不至于爆int,long long的数M..让在题目范围内..b如何多..都达不到M..那么表示状态下值为a*M+b

                 输出答案时...P/M为第一个最优的...P%M为保证第一个最优下第二个最优

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1e3+20, M = 30005, mod = 1e9+7, inf = 0x3f3f3f3f;
typedef long long ll;
//不同为1,相同为0
vector<int > G[N];
int n,m,vis[N],T,ans,dp[N][2];
void dfs(int u) {
    dp[u][0] = 0;
    dp[u][1] = M+1;
    vis[u] = 1;
    for(int i=0;i<G[u].size();i++) {
        int to = G[u][i];
        if(vis[to]) continue;
        dfs(to);
        dp[u][0]+=dp[to][1];
        dp[u][1] += min(dp[to][1]-1,dp[to][0]+1);
    }
}
int main() {
    scanf("%d",&T);
    while(T--) {
        for(int i=0;i<N;i++) G[i].clear(), vis[i] = 0;
        scanf("%d%d",&n,&m);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++) {
            int a,b;
            scanf("%d%d",&a,&b);
            a++,b++;
            G[a].push_back(b);
            G[b].push_back(a);
        }
        ans = 0;
        for(int i=1;i<=n;i++) {
            if(vis[i]) continue;
            dfs(i);
           dp[i][1]--;
            ans += min(dp[i][0], dp[i][1]);
           // cout<<min(dp[i][0], dp[i][1])<<endl;
        }
        printf("%d %d %d\n",ans/M, m-ans%M, ans%M);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/zxhl/p/5352475.html

<think>我们正在讨论的是在Android设备的恢复模式(如TWRP)中使用的shell脚本,因为`ui_print`是常用于此类环境中的命令。在标准的Linuxshell中并没有`ui_print`命令,它通常是由自定义恢复环境提供的。因此,在编写用于恢复刷机的脚本时,我们会使用`ui_print`来在恢复屏幕上显示信息。下面将分别说明这三个命令在恢复脚本中的使用:1.**ui_print**:用于在恢复模式下向用户显示消息。它类似于普通shell脚本中的`echo`,但专门针对恢复模式的输出。在恢复脚本中,我们通常这样使用:```shellui_print"正在安装更新..."```2.**mkdir**:创建目录。在恢复脚本中,我们可能需要创建目录来放置文件。注意,恢复模式下的文件系统可能和正常启动的系统不同,所以需要确保目标分区已经挂载。```shellmkdir-p/system/new_folder```其中`-p`选项允许创建多级目录,并且如果目录已存在也不会报错。3.**cp**:复制文件或目录。在恢复脚本中,我们经常需要复制文件到系统分区。```shellcp/sdcard/update_file/system/app/```注意:在恢复脚本中,我们通常需要先挂载系统分区为可写,否则无法复制文件到系统分区。下面是一个综合示例,假设我们是在一个TWRP恢复脚本中,需要显示一些信息,创建目录并复制文件:```shell#!/sbin/sh#显示开始信息ui_print"开始安装自定义模块..."#挂载系统分区为可读写mount/system#在/system目录下创建一个新的目录ui_print"创建目录..."mkdir-p/system/app/MyApp#复制文件ui_print"复制文件..."cp/sdcard/MyApp.apk/system/app/MyApp/#设置权限(如果需要)ui_print"设置权限..."chmod644/system/app/MyApp/MyApp.apk#卸载系统分区(可选)umount/systemui_print"安装完成!"```注意事项:-恢复脚本通常以`#!/sbin/sh`开头,因为恢复环境中的shell路径通常是`/sbin/sh`。-在操作`/system`分区之前,必须先挂载它。不同的设备可能分区路径不同,所以有时可能需要使用`/system_root`等,具体决于设备。-在恢复脚本中,我们通常需要设置文件的权限,因为从sdcard复制的文件可能权限不正确。-在脚本结束时,可以选择卸载分区,但TWRP通常会在刷机完成后自动卸载。另外,如果是在普通的Linuxshell脚本(非恢复环境)中使用,那么`ui_print`将不可用,此时应使用`echo`代替。例如:```shellecho"正在创建目录..."mkdir-p/path/to/direcho"复制文件..."cpsourcedestination```§§相关问题§§1.在TWRP恢复脚本中如何挂载和卸载分区?2.在恢复脚本中如何设置文件的权限?3.恢复脚本中常见的错误有哪些?如何调试?4.如何制作一个可刷入的ZIP包(包含脚本和文件)?</think>### 在Shell脚本中使用ui_print、mkdir和cp命令 在Shell脚本中,`ui_print`、`mkdir`和`cp`是常用的命令组合,特别是在Android恢复脚本或刷机包中。以下是详细说明和示例: #### 1. **ui_print命令** - **作用**:在恢复模式(如TWRP/CWM)中显示进度信息到用户界面 - **语法**:`ui_print "消息内容"` - **注意**: - 仅适用于Android恢复环境 - 普通Linux终端需替换为`echo` - **示例**: ```shell ui_print "开始安装程序..." ui_print "版本: 1.0" ``` #### 2. **mkdir命令** - **作用**:创建目录 - **常用参数**: - `-p`:递归创建多级目录(目录不存在时自动创建父目录) - `-m`:设置目录权限(如`-m 755`) - **示例**: ```shell mkdir /system/app/MyApp # 创建单级目录 mkdir -p /system/priv-app/MyApp # 递归创建目录 mkdir -m 755 /data/tmp # 创建带权限的目录 ``` #### 3. **cp命令** - **作用**:复制文件/目录 - **常用参数**: - `-r`:递归复制目录 - `-f`:强制覆盖 - `-p`:保留文件属性(权限/时间戳) - **示例**: ```shell cp /sdcard/update.zip /cache/ # 复制文件 cp -rf /tmp/modules/* /system/lib/ # 递归复制目录 cp -p script.sh /system/bin/ # 保留属性复制 ``` --- ### 完整脚本示例 ```shell #!/sbin/sh # 显示安装进度 ui_print "[1/4] 正在创建目录..." mkdir -p /system/app/MyApp mkdir -p /system/priv-app/MyAppExtra ui_print "[2/4] 复制应用文件..." cp -f /sdcard/MyApp.apk /system/app/MyApp/ cp -rf /sdcard/lib/* /system/lib/ ui_print "[3/4] 设置权限..." chmod 644 /system/app/MyApp/MyApp.apk chmod 755 /system/lib/*.so ui_print "[4/4] 安装完成!" ``` --- ### 关键注意事项 1. **环境差异**: - `ui_print`仅在Android恢复环境有效,普通Shell脚本用`echo` ```shell # 通用写法 [ -n "$RECOVERY_OUT" ] && ui_print "消息" || echo "消息" ``` 2. **权限问题**: - 系统目录操作需先挂载分区: ```shell mount /system # 挂载system分区 mkdir /system/new_folder umount /system # 操作后卸载 ``` 3. **错误处理**: ```shell if ! cp file /destination; then ui_print "错误: 文件复制失败!" exit 1 fi ``` 4. **路径规范**: - 使用绝对路径避免歧义 - 特殊字符需转义:`cp "文件 名.txt" /dest` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值