UVA-1218 Perfect Service
2015-12-08 21:35
423 查看
Brief description
略
Algorithm analyse
首先对这个题目分析。
首先想到的是类似前面的最大独立集,但这里是求最小独立集。
后来发现并不是。还是要好好分析。
学习别人的思想。
首先,对于任一节点。
1.该节点是服务器,其子节点可以是服务器也可以不是子服务器。dp[0]+=min(dp[v][0],dp[v][1]);
2.该节点不是服务器 a.其父亲是服务器,那么所有儿子不是服务器。dp[u][1]+=dp[v][2];
b.其父亲不是服务器,那么所有儿子中只有一个是服务器(这个要遍历),这里面有2个for循环是n^2的复杂度,不允许,可以根据前面已知的条件来。dp[u][1]是所有的不是子节点,减去]dp[v][2]加上dp[v][0] 就行了.
总体思路就出来了。但是实现时还是WR好久,也看了几个题解才做出来。
错误点
1.这是个无根树,但是我在建树的时候建立了方向(类似前面的题),这样就导致有的点被漏掉,然后就是无向图的实现我还是
好弱,看题解发现了2种方法,等等我都贴上来。
2.在for(int i=0;i<G[u].size();i++)的循环中
我直接dp[u][2]=min(dp[u][2],dp[v][0]-dp[v][2]+dp[u][1]);这导致了一个问题,我的dp[u][1]并没有全部加完。导致算出的 结果小。WR了n次。后来还是POJ上面的dis的测试数据发现的(ORZ,poj上面数据太弱,就是一个并查集。)
3.在结果的比较中,只需比较dp[][0]和dp[][2],因为没有父节点。
Code
LRJ的代码。
感觉LRJ的代码太繁琐了,但还是十分严谨,还是贴上来。
以前我总是对这个存在畏惧感,但是,一点都不难。现在再看,很好理解!相信自己。
对于nxt的理解。
[u]这是为了以后for循环中的遍历,到-1停止.
参考代码
略
Algorithm analyse
首先对这个题目分析。
首先想到的是类似前面的最大独立集,但这里是求最小独立集。
后来发现并不是。还是要好好分析。
学习别人的思想。
首先,对于任一节点。
1.该节点是服务器,其子节点可以是服务器也可以不是子服务器。dp[0]+=min(dp[v][0],dp[v][1]);
2.该节点不是服务器 a.其父亲是服务器,那么所有儿子不是服务器。dp[u][1]+=dp[v][2];
b.其父亲不是服务器,那么所有儿子中只有一个是服务器(这个要遍历),这里面有2个for循环是n^2的复杂度,不允许,可以根据前面已知的条件来。dp[u][1]是所有的不是子节点,减去]dp[v][2]加上dp[v][0] 就行了.
总体思路就出来了。但是实现时还是WR好久,也看了几个题解才做出来。
错误点
1.这是个无根树,但是我在建树的时候建立了方向(类似前面的题),这样就导致有的点被漏掉,然后就是无向图的实现我还是
好弱,看题解发现了2种方法,等等我都贴上来。
2.在for(int i=0;i<G[u].size();i++)的循环中
我直接dp[u][2]=min(dp[u][2],dp[v][0]-dp[v][2]+dp[u][1]);这导致了一个问题,我的dp[u][1]并没有全部加完。导致算出的 结果小。WR了n次。后来还是POJ上面的dis的测试数据发现的(ORZ,poj上面数据太弱,就是一个并查集。)
3.在结果的比较中,只需比较dp[][0]和dp[][2],因为没有父节点。
Code
LRJ的代码。
感觉LRJ的代码太繁琐了,但还是十分严谨,还是贴上来。
// UVa1218 Perfect Service // Rujia Liu #include<cstdio> #include<vector> #include<algorithm> using namespace std; const int maxn = 10000 + 5; const int INF = 1000000000; vector<int> G[maxn], vertices; int p[maxn], d[maxn][3]; // build a rooted tree and dfs sequence void dfs(int u, int fa) { vertices.push_back(u); p[u] = fa; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(v != fa) dfs(v, u); } } int main() { int n; while(scanf("%d", &n) == 1) { for(int i = 0; i < n; i++) G[i].clear(); for(int i = 0; i < n-1; i++) { int u, v; scanf("%d%d", &u, &v); u--; v--; G[u].push_back(v); G[v].push_back(u); } vertices.clear(); dfs(0, -1); for(int i = vertices.size()-1; i >= 0; i--) { int u = vertices[i]; d[u][0] = 1; d[u][1] = 0; for(int j = 0; j < G[u].size(); j++) { int v = G[u][j]; if(v == p[u]) continue; d[u][0] += min(d[v][0], d[v][1]); // u is server d[u][1] += d[v][2]; // u is not server, u's father is server if(d[u][0] > INF) d[u][0] = INF; // avoid overflow! if(d[u][1] > INF) d[u][1] = INF; } d[u][2] = INF; for(int j = 0; j < G[u].size(); j++) { int v = G[u][j]; if(v == p[u]) continue; d[u][2] = min(d[u][2], d[u][1] - d[v][2] + d[v][0]); // neither u or father is server } } printf("%d\n", min(d[0][0], d[0][2])); scanf("%d", &n); // flag } return 0; }然后是链表实现无向图的。
以前我总是对这个存在畏惧感,但是,一点都不难。现在再看,很好理解!相信自己。
对于nxt的理解。
[u]这是为了以后for循环中的遍历,到-1停止.
参考代码
#include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-10) #define INF 1e6 #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; const int maxn=11000; struct Edge { int to; int nxt; }edge[maxn*2]; int Adj[maxn],Size; int dp[maxn][3],n; void init() { Size=0; for(int i=0;i<n+10;i++) { Adj[i]=-1; dp[i][0]=1; dp[i][1]=0; dp[i][2]=INF; } } void add_edge(int u,int v) { edge[Size].to=v; edge[Size].nxt=Adj[u]; Adj[u]=Size++; } void dfs(int u,int fa) { for(int i=Adj[u];~i;i=edge[i].nxt) { int v=edge[i].to; if(v==fa) continue; dfs(v,u); dp[u][0]+=min(dp[v][0],dp[v][1]); dp[u][1]+=dp[v][2]; dp[u][2]=min(dp[u][2],dp[v][0]-dp[v][2]); } dp[u][2]+=dp[u][1]; } int main() { while(~scanf("%d",&n)) { if(n==-1) break; else if(n==0) continue; init(); for(int i=0;i<n-1;i++) { int a,b; scanf("%d%d",&a,&b); add_edge(a,b); add_edge(b,a); } dfs(1,0); printf("%d\n",min(dp[1][0],dp[1][2])); } return 0; }vector
#include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-10) #define INF 1e6 #define clr(x) memset((x),0,sizeof (x)) #define cp(a,b) memcpy((a),(b),sizeof (b)) typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> P; const int maxn=10010; int dp[maxn][3]; int n,root; vector<int> G[maxn]; void init(int t) { for(int i=0;i<t+10;i++) G[i].clear(); for(int i=0;i<t+10;i++) { dp[i][0]=1; dp[i][1]=0; dp[i][2]=INF; } } void dfs(int u,int fa) { for(int i=0;i<G[u].size();i++) { int v=G[u][i]; if(v==fa) continue; dfs(v,u); dp[u][0]+=min(dp[v][0],dp[v][1]); dp[u][1]+=dp[v][2]; dp[u][2]=min(dp[u][2],dp[v][0]-dp[v][2]); } dp[u][2]+=dp[u][1]; } int main() { while(~scanf("%d",&n)) { if(n==-1) break; if(n==0) continue; init(n); int a,b; n--; while(n--) { scanf("%d%d",&a,&b); G[a].pb(b); G[b].pb(a); } dfs(1,0); printf("%d\n",min(dp[1][0],dp[1][2])); } return 0; }
相关文章推荐
- html5结合JavaScript实现龙播图
- js判断MAC地址
- js判断浏览器在PC中打开还是移动设备中打开
- Javascript中最常用的55个经典技巧
- html+css+javascript 基础知识(二)
- jquery-2.1.4 源码解读(2):jQuery.fn.init 构造函数解读
- 学习贪吃蛇JS项目实战笔记3
- 学习贪吃蛇JS项目实战笔记2
- 《剑指offer》——字符流中第一个不重复的字符
- html+css+javascript 基础知识(一)
- javascript如何写热点图
- json
- 贪吃蛇游戏实战学习JS
- js实时显示系统时间
- 轻松学习JavaScript十二:JavaScript基于面向对象之创建对象(二)
- Jquery 中DOM对象操作
- phpstorm中实时将SCSS编译为CSS
- js的浮点运算问题
- JSP语法的练习
- 七牛---关于Node.js SDK的各种Demo