HDU--1054
Strategic Game
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5436 Accepted Submission(s): 2516
Problem Description
Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is very sad. Now he has the following problem. He must defend a medieval city, the roads of which form a tree. He has to put the minimum number of soldiers on the nodes so that they can observe all the edges. Can you help him?
Your program should find the minimum number of soldiers that Bob has to put for a given tree.
The input file contains several data sets in text format. Each data set represents a tree with the following description:
the number of nodes the description of each node in the following format node_identifier:(number_of_roads) node_identifier1 node_identifier2 ... node_identifier or node_identifier:(0)
The node identifiers are integer numbers between 0 and n-1, for n nodes (0 < n <= 1500). Every edge appears only once in the input data.
For example for the tree:
the solution is one soldier ( at the node 1).
The output should be printed on the standard output. For each given input data set, print one integer number in a single line that gives the result (the minimum number of soldiers). An example is given in the following table:
Your program should find the minimum number of soldiers that Bob has to put for a given tree.
The input file contains several data sets in text format. Each data set represents a tree with the following description:
the number of nodes the description of each node in the following format node_identifier:(number_of_roads) node_identifier1 node_identifier2 ... node_identifier or node_identifier:(0)
The node identifiers are integer numbers between 0 and n-1, for n nodes (0 < n <= 1500). Every edge appears only once in the input data.
For example for the tree:
the solution is one soldier ( at the node 1).
The output should be printed on the standard output. For each given input data set, print one integer number in a single line that gives the result (the minimum number of soldiers). An example is given in the following table:
Sample Input
4
0:(1) 1
1:(2) 2 3
2:(0)
3:(0)
5
3:(3) 1 4 2
1:(1) 0
2:(0)
0:(0)
4:(0)
Sample Output
1
2
分析:
在树上做一个动态规划
【状态】:
dp[i][0] 为以 i 为根节点,并且该节点不放,所需要的最少的点数
dp[i][1] 为以 i 为根节点,并且该节点放,所需要的最少的点数
【转移方程】:
dp[i][0]=sum(dp[son[i][j]][1]) 该点不放的话,那么它的儿子节点必须都放,这样之间的边才可以被覆盖
dp[i][1]=sum(min(dp[son[i][j]][0],dp[son[i][j]][1])) 该点放的话,那么它的儿子节点就有两种决策,一种是放,一种是不放,取 min 就行了
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
vector<int > vc[1503];
int dp[1503][2],flag[1503];
void dfs(int a)
{
dp[a][0]=0;
dp[a][1]=1;
flag[a]=1; //标记为访问状态
for(int i=0;i<vc[a].size();i++)
{
int k=vc[a][i];
if(flag[k]) continue; // 如果该子节点已经访问了,则访问下一子节点;
dfs(k); //否则访问该子节点
//核心代码:如果当前节点处无哨兵,则其所有子节点处都应该有
//如果有哨兵,则选子节点所需哨兵少的情况
dp[a][0]+=dp[k][1];
dp[a][1]+=min(dp[k][0],dp[k][1]);
}
}
int main()
{
int m,n,k,r;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++) vc[i].clear();
for(int i=0;i<n;i++)
{
scanf("%d:(%d)",&m,&k);
for(int j=0;j<k;j++)
{
scanf("%d",&r);
vc[m].push_back(r);
vc[r].push_back(m);
}
}
memset(flag,0,sizeof(flag));
memset(dp,0,sizeof(dp));
dfs(0);
int total=min(dp[0][0],dp[0][1]);
cout<<total<<endl;
}
return 0;
}
以下是(WA的贪心代码)
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef struct Node
{
int k;
int sum;
//int flag;
}node;
node c[1503];
int flag[1503];
int arr[1503][1503]; //邻接矩阵
bool cmp(node a,node b)
{
if(a.sum==b.sum) return a.k<b.k;
else return a.sum>b.sum;
}
int main()
{
int n,m;
while(scanf("%d",&n)!=EOF)
{
memset(arr,0,sizeof(arr));
memset(flag,1,sizeof(flag)); //将标识初始化
for(int i=0;i<n;i++)
{
scanf("%d:(%d)",&c[i].k,&c[i].sum);
//c[i].flag=1;
for(int j=0;j<c[i].sum;j++)
{
cin>>m;
arr[m][c[i].k]=arr[c[i].k][m]=1;
}
}
sort(c,c+n,cmp);
//for(int i1=0;i1<n;i1++)
//{
// cout<<c[i1].sum<<" "<<c[i1].k<<endl;
// }
int t_num=0;
for(int h=0;h<n;h++)
{
if(flag[c[h].k])
{
flag[c[h].k]=0;
t_num++;
//cout<<"第一次处理 "<<c[h].k<<" ";
for(int i=0;i<n;i++)
{
if(arr[i][c[h].k] && flag[i])
{
flag[i]=0;
//cout<<"第二次处理 "<<i <<endl;
}
}
}
}
cout<<t_num<<endl;
}
return 0;
}
思路:由于每条边只记录一次,所以使用贪心算法,按边数降序排列:(Wrong Answer)
浙公网安备 33010602011771号