贪婪与动态规划
greedy vs dynamic programming
Xaero 住在一个叫做 Hackland 的国家。 Hackland 具有树状结构,N 个城市由 N−1 条双向道路连接。每个城市的索引都在[1,N]之间,没有两个城市的索引相同。
Hackland总裁认为在城市内出行是安全的。但是,由于哈克兰的照明条件差,在城市 A 到另一个城市 B 之间旅行并不安全。
为了保证人们从一个城市到另一个城市的安全,哈克兰总统决定在国内安装一些灯。每个城市最多可以安装 1 盏灯。甚至有可能一些城市已经安装了灯。根据总统的说法,从一个城市 A 到另一个城市 B 的旅行,如果该路径上至少有 1 个城市安装了灯,则被认为是安全的。
Xaero 知道 Hackland 的预算非常有限。因此,他想帮助他的总统,告诉他最少要安装多少盏灯,这样从一个城市到另一个城市的旅行就变得安全了。
输入格式
输入的第一行包含一个整数T,表示测试用例的数量。每个测试用例的第一行包含一个整数 N,表示称为 Hackland 的国家中的城市数。每个测试用例的下一行包含 N space 个分隔的整数,表示国家的初始配置,即第 i 个位置的“0”表示第 i 个城市没有安装灯,而第 i 个位置的“1”表示有灯已经安装在第i个城市。每个测试用例接下来的 N−1 行包含一对整数 U 和 V,表示城市 U 和城市 V 之间存在双向道路。
我的方法::
对于这个问题,我使用的方法是,我总是选择具有最大度数的节点。照亮它(即使其 deg 为 0,并将其相邻节点的 deg 减少 1),我将继续执行此过程,直到任何节点的 deg 大于零。对于已经变亮的节点,我将它们的 deg 设置为 0,并将其相邻节点的 deg 减少 1。但是我的答案对于某些测试用例不正确??任何人都可以提出我的方法有什么问题吗??
我在这里分享代码...
#include<bits/stdc++.h>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int T, i, j, max, max_index, index, count, strt, end , N ;
bool flag ;
cin>> T ;
while(T--)
{
cin >> N ;
count = 0 ;
vector<vector<int>> tree ;
vector<int> init(N+1) ;
vector<int> deg(N+1) ;
fill(deg.begin(),deg.end(),0) ;
tree.resize(N+1) ;
for(i=1; i<=N; i++)
cin >> init[i] ;
for(i=0 ; i < N-1 ; i++)
{
cin>>strt>>end ;
tree[strt].push_back(end) ;
tree[end].push_back(strt) ;
deg[strt] = deg[strt] + 1 ;
deg[end] = deg[end] + 1 ;
}
for(i=1; i <=N ; i++)
{
if(init[i]==1)
{
deg[i] = 0 ;
for(j=0 ; j < tree[i].size(); j++)
{
index = tree[i][j] ;
deg[index] = deg[index] -1 ;
}
}
}
while(1){
flag = false ; //
for(i=1 ; i<= N ; i++)
{
if(deg[i] > 0){
flag = true ;
break ;
}
}
if(flag==false)
break ;
max = deg[1] ; //
max_index = 1; //
for(i=2; i <= N ;i++)
{
if(deg[i] > max)
{
max = deg[i] ;
max_index = i ;
}
}
// cout<<"max_index "<<max_index <<endl ;
count = count + 1 ; //
deg[max_index] = 0 ;
for(j=0; j < tree[max_index].size() ; j++)
{
index = tree[max_index][j] ;
deg[index] = deg[index]- 1 ; //
}
}
cout<<count<<endl ;
}
return 0;
}
你的方法是贪心的,而真正的解决方案是基于 DP(顺便说一句,正如你的标题所暗示的)。有很多你可能出错的例子,但这是我认为的一个 - 当多个节点具有相同的度时你应该特别小心并明智地选择:
1
5
00000
1 2
1 3
2 4
3 5
请注意,即使您为此测试用例输出了正确答案,那也完全是运气问题 - 这里有三个度数为 2 的节点,最好的解决方案是只减轻其中两个 - 2 和 3。根据您给出相等节点的顺序,您最终可能会点亮错误的节点 1。请注意 - 还有许多其他情况下您的解决方案是错误的,这只是我认为最简单的。
Xaero 住在一个叫做 Hackland 的国家。 Hackland 具有树状结构,N 个城市由 N−1 条双向道路连接。每个城市的索引都在[1,N]之间,没有两个城市的索引相同。
Hackland总裁认为在城市内出行是安全的。但是,由于哈克兰的照明条件差,在城市 A 到另一个城市 B 之间旅行并不安全。
为了保证人们从一个城市到另一个城市的安全,哈克兰总统决定在国内安装一些灯。每个城市最多可以安装 1 盏灯。甚至有可能一些城市已经安装了灯。根据总统的说法,从一个城市 A 到另一个城市 B 的旅行,如果该路径上至少有 1 个城市安装了灯,则被认为是安全的。
Xaero 知道 Hackland 的预算非常有限。因此,他想帮助他的总统,告诉他最少要安装多少盏灯,这样从一个城市到另一个城市的旅行就变得安全了。
输入格式
输入的第一行包含一个整数T,表示测试用例的数量。每个测试用例的第一行包含一个整数 N,表示称为 Hackland 的国家中的城市数。每个测试用例的下一行包含 N space 个分隔的整数,表示国家的初始配置,即第 i 个位置的“0”表示第 i 个城市没有安装灯,而第 i 个位置的“1”表示有灯已经安装在第i个城市。每个测试用例接下来的 N−1 行包含一对整数 U 和 V,表示城市 U 和城市 V 之间存在双向道路。
我的方法::
对于这个问题,我使用的方法是,我总是选择具有最大度数的节点。照亮它(即使其 deg 为 0,并将其相邻节点的 deg 减少 1),我将继续执行此过程,直到任何节点的 deg 大于零。对于已经变亮的节点,我将它们的 deg 设置为 0,并将其相邻节点的 deg 减少 1。但是我的答案对于某些测试用例不正确??任何人都可以提出我的方法有什么问题吗??
我在这里分享代码...
#include<bits/stdc++.h>
using namespace std;
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int T, i, j, max, max_index, index, count, strt, end , N ;
bool flag ;
cin>> T ;
while(T--)
{
cin >> N ;
count = 0 ;
vector<vector<int>> tree ;
vector<int> init(N+1) ;
vector<int> deg(N+1) ;
fill(deg.begin(),deg.end(),0) ;
tree.resize(N+1) ;
for(i=1; i<=N; i++)
cin >> init[i] ;
for(i=0 ; i < N-1 ; i++)
{
cin>>strt>>end ;
tree[strt].push_back(end) ;
tree[end].push_back(strt) ;
deg[strt] = deg[strt] + 1 ;
deg[end] = deg[end] + 1 ;
}
for(i=1; i <=N ; i++)
{
if(init[i]==1)
{
deg[i] = 0 ;
for(j=0 ; j < tree[i].size(); j++)
{
index = tree[i][j] ;
deg[index] = deg[index] -1 ;
}
}
}
while(1){
flag = false ; //
for(i=1 ; i<= N ; i++)
{
if(deg[i] > 0){
flag = true ;
break ;
}
}
if(flag==false)
break ;
max = deg[1] ; //
max_index = 1; //
for(i=2; i <= N ;i++)
{
if(deg[i] > max)
{
max = deg[i] ;
max_index = i ;
}
}
// cout<<"max_index "<<max_index <<endl ;
count = count + 1 ; //
deg[max_index] = 0 ;
for(j=0; j < tree[max_index].size() ; j++)
{
index = tree[max_index][j] ;
deg[index] = deg[index]- 1 ; //
}
}
cout<<count<<endl ;
}
return 0;
}
你的方法是贪心的,而真正的解决方案是基于 DP(顺便说一句,正如你的标题所暗示的)。有很多你可能出错的例子,但这是我认为的一个 - 当多个节点具有相同的度时你应该特别小心并明智地选择:
1
5
00000
1 2
1 3
2 4
3 5
请注意,即使您为此测试用例输出了正确答案,那也完全是运气问题 - 这里有三个度数为 2 的节点,最好的解决方案是只减轻其中两个 - 2 和 3。根据您给出相等节点的顺序,您最终可能会点亮错误的节点 1。请注意 - 还有许多其他情况下您的解决方案是错误的,这只是我认为最简单的。