这题做的心塞。。。

整个思路非常清晰,d[i][0]表示第i个结点不设置监察的情况下至少需要的数量;d[i][1]表示第i个结点设置检查的情况下的最小需要的数量。

状态转移方程见代码。

但是万万没想到的是,在实现过程中修改了4遍代码,wa了若干次才AC。。。。

下面来总结一下各种wa代码:

版本1:开二维数组存储树(本质上是邻接矩阵存储,把树存储成图),报错TLE。这时候第一感觉是每次更新d[i]的时候都需要遍历一遍邻接表中的所有结点不管是否是子节点都需要遍历。也就是完整的n*n复杂度。因此有了第一次修改,考虑存储的时候用vector只存储子节点从而减少遍历时的数量。(见版本2)

上代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<algorithm>
using namespace std;
//TLE 应该是在更新d[i][]的时候每次都需要遍历n个数,复杂度为o(n^2)
const int maxn=;
int d[maxn][];
int gra[maxn][maxn];
int flag[maxn];
int n;
void dp(int cur){
flag[cur]=;
if(d[cur][]>=||d[cur][]>=){
return;
}
int leaf=;
for(int i=;i<n;i++){
if(gra[cur][i]&&flag[i]!=){
leaf=;
dp(i);
if(d[cur][]==-)d[cur][]=;
if(d[cur][]==-)d[cur][]=;
d[cur][]+=d[i][];
d[cur][]+=min(d[i][],d[i][]);
}
}
d[cur][]++;
if(leaf==){
d[cur][]=;d[cur][]=;
}
}
int main(void){
while(scanf("%d",&n)){
memset(flag,,sizeof(flag));
memset(gra,,sizeof(gra));
memset(d,-,sizeof(d));
int x,cnt;
int num=n;
while(num--){
scanf("%d:(%d)",&x,&cnt);
while(cnt--){
int tem;
scanf("%d",&tem);
gra[x][tem]=;
gra[tem][x]=;
}
}
dp(x);
int ans=min(d[x][],d[x][]);
cout<<ans<<endl;
}
return ;
}

版本2代码:拟通过vector减少遍历的结点个数(只遍历子节点)。这次修改后果然没有报TLE,但是报了另外一个错:MLE。。。

所以说使用stl还是要慎重。。这时再看了一遍输入样例,发现其实这个输入是按标准的有向树输入的;换句话说根本不需要构造图来解,只需要每个结点记录其父亲即可。

这样一算,存储的数据量瞬间减半。因此有了版本3代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<sstream>
#include<algorithm>
#include<vector>
using namespace std;
//memory limit
const int maxn=;
int d[maxn][];
//int gra[maxn][maxn];
vector<int>gra[maxn];
bool flag[maxn];
int n;
void dp(int cur){
flag[cur]=;
if(d[cur][]>=||d[cur][]>=){
return;
}
else{
int leaf=;
for(int i=;i<gra[cur].size();i++){
int next=gra[cur][i];
if(flag[next]==){
leaf=;
dp(next);
if(d[cur][]==-)d[cur][]=;
if(d[cur][]==-)d[cur][]=;
d[cur][]+=d[next][];
d[cur][]+=min(d[next][],d[next][]);
}
}
d[cur][]++;
if(leaf==){
d[cur][]=;d[cur][]=;
}
}
}
int main(void){
while(scanf("%d",&n)!=EOF){
memset(flag,,sizeof(flag));
memset(gra,,sizeof(gra));
memset(d,-,sizeof(d));
int x,cnt;
int num=n;
while(num--){
scanf("%d:(%d)",&x,&cnt);
while(cnt--){
int tem;
scanf("%d",&tem);
gra[x].push_back(tem);
gra[tem].push_back(x);
}
}
dp(x);
int ans=min(d[x][],d[x][]);
cout<<ans<<endl;
}
return ;
}

版本3代码:本来以为这个可以直接AC的,结果又一次TLE。。。而且这次的错误找了好久没想到。

最后发现出现在了scanf上。。。

版本3中的代码while(scanf("%d",&n)) 改成while(scanf("%d",&n)!=EOF)或者while(~scanf("%d",&n))就AC了(真的是,秀了一波骚操作。侧面反映基础不太扎实。。。。)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=;
int d[maxn][];
int pre[maxn];
int childcnt[maxn];
int n;
void dp(int cur){
if(d[cur][]>=||d[cur][]>=){
return;
}
if(childcnt[cur]==){
d[cur][]=;d[cur][]=;
return ;
}
for(int i=;i<n;i++){
if(pre[i]==cur){
dp(i);
if(d[cur][]==-)d[cur][]=;
if(d[cur][]==-)d[cur][]=;
d[cur][]+=d[i][];
d[cur][]+=min(d[i][],d[i][]);
}
}
d[cur][]++;
}
int main(void){
while(scanf("%d",&n)){
memset(pre,-,sizeof(pre));
memset(d,-,sizeof(d));
int x,cnt,root=-;
int num=n;
while(num--){
scanf("%d:(%d)",&x,&cnt);
childcnt[x]=cnt;
if(root==-)root=x;
while(cnt--){
int tem;
scanf("%d",&tem);
pre[tem]=x;
if(tem==root){
root=x;
}
}
}
dp(root);
int ans=min(d[root][],d[root][]);
printf("%d\n",ans);
}
return ;
}

AC代码如下:哎,任重而道远,,,太菜了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=;
int d[maxn][];
int pre[maxn];
int childcnt[maxn];
int n;
void dp(int cur){
if(d[cur][]>=||d[cur][]>=){
return;
}
if(childcnt[cur]==){
d[cur][]=;d[cur][]=;
return ;
}
for(int i=;i<n;i++){
if(pre[i]==cur){
dp(i);
if(d[cur][]==-)d[cur][]=;
if(d[cur][]==-)d[cur][]=;
d[cur][]+=d[i][];
d[cur][]+=min(d[i][],d[i][]);
}
}
d[cur][]++;
}
int main(void){
while(scanf("%d",&n)!=EOF){//万万没想到是这里出错
memset(pre,-,sizeof(pre));
memset(d,-,sizeof(d));
int x,cnt,root=-;
int num=n;
while(num--){
scanf("%d:(%d)",&x,&cnt);
childcnt[x]=cnt;
if(root==-)root=x;
while(cnt--){
int tem;
scanf("%d",&tem);
pre[tem]=x;
if(tem==root){
root=x;
}
}
}
dp(root);
int ans=min(d[root][],d[root][]);
printf("%d\n",ans);
}
return ;
}

POJ - 1463 Strategic game (树状动态规划)的更多相关文章

  1. POJ 2352 Stars(树状数组)

    Stars Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 30496   Accepted: 13316 Descripti ...

  2. POJ 3321 Apple Tree (树状数组+dfs序)

    题目链接:http://poj.org/problem?id=3321 给你n个点,n-1条边,1为根节点.给你m条操作,C操作是将x点变反(1变0,0变1),Q操作是询问x节点以及它子树的值之和.初 ...

  3. poj 2828 Buy Tickets(树状数组 | 线段树)

    题目链接:poj 2828 Buy Tickets 题目大意:给定N,表示有个人,给定每一个人站入的位置,以及这个人的权值,如今按队列的顺序输出每一个人的权值. 解题思路:第K大元素,非常巧妙,将人入 ...

  4. poj 2299 Ultra-QuickSort(树状数组求逆序数+离散化)

    题目链接:http://poj.org/problem?id=2299 Description In this problem, you have to analyze a particular so ...

  5. poj 2299 Ultra-QuickSort(树状数组求逆序数)

    链接:http://poj.org/problem?id=2299 题意:给出n个数,求将这n个数从小到大排序,求使用快排的需要交换的次数. 分析:由快排的性质很容易发现,只需要求每个数的逆序数累加起 ...

  6. poj 3067 Japan(树状数组求逆序数)

    链接:http://poj.org/problem?id=3067 题意:左边有n个城市,右边有m个城市,建k条道路,问有这k条道路中有多少个交点. 分析:将城市按x和y从小到大排序,对于每条道路,求 ...

  7. POJ 2299 Ultra-QuickSort(树状数组+离散化)

    http://poj.org/problem?id=2299 题意:给出一组数,求逆序对. 思路: 这道题可以用树状数组解决,但是在此之前,需要对数据进行一下预处理. 这道题目的数据可以大到999,9 ...

  8. POJ 3067 Japan 【树状数组经典】

    题目链接:POJ 3067 Japan Japan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 32076   Accep ...

  9. POJ 2155 Matrix(树状数组+容斥原理)

    [题目链接] http://poj.org/problem?id=2155 [题目大意] 要求维护两个操作,矩阵翻转和单点查询 [题解] 树状数组可以处理前缀和问题,前缀之间进行容斥即可得到答案. [ ...

随机推荐

  1. MQTT的学习研究(十六) MQTT的Mosquitto的window安装部署

    在mqtt的官方网站,有许多mqtt,其中:MosquittoAn Open Source MQTT server with C, C++, Python and Javascript clients ...

  2. Jenkins反序列化漏洞cve-2017-1000353

    一.漏洞原理: 本地没有环境:参考:https://blogs.securiteam.com/index.php/archives/3171    进行学习理解记录. 首先这是一个java反序列化漏洞 ...

  3. Fluent Nhibernate Mapping for Sql Views

    Views are mapped the same way tables are mapped except that you should put Readonly() in the mapping ...

  4. 【BZOJ3312】[Usaco2013 Nov]No Change 状压DP+二分

    [BZOJ3312][Usaco2013 Nov]No Change Description Farmer John is at the market to purchase supplies for ...

  5. iOS CoreMotion 纪录步数

    - (void)startUpdateAccelerometer{    /* 设置采样的频率,单位是秒 */    NSTimeInterval updateInterval = 0.05; // ...

  6. Linux创建Python虚拟环境

    Linux创建Python虚拟环境 安装 pip install virtualenv 基本使用 为一个工程创建一个虚拟环境: $ cd my_project $ virtualenv venv #v ...

  7. javascript 执行环境,作用域链和闭包

    首先看下这条语句: (function($) {…})(jQuery): 1.原理: function(arg){…}这就定义了一个匿名函数,参数为arg 而调用函数时,是在函数后面写上括号和实参的, ...

  8. 使用CXF做webservice整合现有项目的例子

    从网上看了很多CXF的资料,大部分都是单独的作为一个webservice项目,对于在现有的spring项目上提供webservice服务的例子基本没有找到. 我做的这个例子是介绍怎么把cxf整合到现有 ...

  9. load_1m

  10. 20144306《网络对抗》MAL_后门原理与实践

    本期收获 1.了解后门的基本概念. 2.Netcat.socat.MSF meterpreter的使用(MSF meterpreter实在太好玩了) 3.后门软件的启动方式: Windows任务计划程 ...