zoukankan      html  css  js  c++  java
  • Noip2003提高组

    又逢运动会,又是一个在机房刷题的日子。


    t1.神经网络

    题目

    题意:略。

    思路:[拓扑排序+模拟] 先处理出一个拓扑序,然后直接模拟即可。

    Code:

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <vector>
    using namespace std;
    //Mystery_Sky
    //
    #define M 1000100
    #define INF 0x3f3f3f3f
    #define ll long long
    inline int read()
    {
    	int x=0,f=1; char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    
    struct Edge{
    	int to, next, w;
    }edge[M];
    int n, m;
    int c[M], u[M], pos[M];
    int cnt, head[M], dis[M], out[M], ind[M];
    queue <int> q;
    vector <int> t;
    
    inline void add_edge(int u, int v, int w)
    {
    	edge[++cnt].to = v;
    	edge[cnt].next = head[u];
    	edge[cnt].w = w;
    	head[u] = cnt;
    }
    
    inline void topo()
    {
    	for(int i = 1; i <= n; i++) 
    		if(!ind[i]) q.push(i), pos[i] = 1;
    	while(!q.empty()) {
    		int u = q.front(); q.pop();
    		t.push_back(u); 
    		for(int i = head[u]; i; i = edge[i].next) {
    			int v = edge[i].to;
    			ind[v]--;
    			if(!ind[v]) q.push(v); 
    		}
    	} 
    }
    
    int main() {
    	n = read(), m = read();
    	for(int i = 1; i <= n; i++) c[i] = read(), u[i] = read();
    	for(int i = 1; i <= m; i++) {
    		int u = read(), v = read(), w = read();
    		add_edge(u, v, w);
    		ind[v]++;
    		out[u]++;
    	}
    	topo();
    	for(int a = 0; a < n; a++) {
    		int i = t[a];
    		if(pos[i] != 1) c[i] -= u[i];
    		if(c[i] > 0) {
    			for(int x = head[i]; x; x = edge[x].next) {
    				int v = edge[x].to;
    				c[v] += edge[x].w * c[i];
    			}
    		}
    	}
    	bool flag = false;
    	for(int i = 1; i <= n; i++) {
    		if(out[i] == 0 && c[i] > 0) printf("%d %d
    ", i, c[i]), flag = true;
    	}
    	if(!flag) printf("NULL
    ");
    	return 0;
    }
    

    t2.侦探推理

    题目

    题意:有M个人,其中N个人只说谎话,其余的人只说实话,有P条证词。然后根据证词找出罪犯。

    思路:[模拟] 不会,过

    Code:

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <ctime> 
    //Mystery_Sky
    //QWQ
    using namespace std;
    int main (){
        srand(time(0));
        if(rand()%2) printf("Cannot Determine
    ");
        else printf("Impossible
    ");
        return 0;
    }
    

    t3.加分二叉树

    题目

    题意:自行领悟,略。

    思路:[dp] 之前在外面培训的时候讲过,然而我好像忘了。设f[i][j]表示从i到j的这一段树的加分,那么枚举i到j之间的节点做根即可。f[i][j] = max{f[i][k-1] + f[k+1][j] + a[k]}(i<k<j)。对于第二问的输出前序遍历,设tree[i][j]为i到j的根节点,最后输出即可。

    Code:

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <vector>
    using namespace std;
    //Mystery_Sky
    //
    #define M 30
    #define INF 0x3f3f3f3f
    #define ll long long
    inline int read()
    {
    	int x=0,f=1; char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    int n;
    ll f[M][M], tree[M][M], a[M];
    
    inline void print(int l, int r)
    {
    	if(l > r) return;
    	printf("%lld ", tree[l][r]);
    	if(l == r) return;
    	print(l, tree[l][r] - 1);
    	print(tree[l][r] + 1, r);
    }
    
    int main() {
    	n = read();
    	for(int i = 1; i <= n; i++) {
    		a[i] = read();
    		tree[i][i] = i;
    		f[i][i] = a[i];
    	}
    	for(int len = 1; len <= n; len++) {
    		for(int i = 1; i + len <= n; i++) {
    			int j = i + len;
    			tree[i][j] = i;
    			f[i][j] = f[i][i] + f[i+1][j];
    			for(int k = i + 1; k < j; k++) {
    				if(f[i][k-1] * f[k+1][j] + f[k][k] > f[i][j]) {
    					f[i][j] = f[i][k-1] * f[k+1][j] + f[k][k];
    					tree[i][j] = k;
    				}
    			}
    		}
    	}
    	printf("%lld
    ", f[1][n]);
    	print(1, n);
    	return 0;
    }
    

    t4.传染病控制

    题目

    题意:给定一棵树,从根节点开始逐步往下,每次感染一层,每次可以切断树上的一条边,求最少感染人数。

    思路:[贪心(错误)]
    拿到这道题,首先想到了贪心,就是每次割边的时候割掉与子树最大的点所连的边。然后得了90分。但是事实上这道题目贪心是错误的,能得到90分完全是因为数据过水。
    为什么贪心错了呢?举个栗子:如果当前节点有一个左子树和一个右子树,其中左子树是一个很长很长的链,而右子树是一棵比左子树略短的二叉树,那么我们显然应该割掉与右子树相连的边,而贪心却是去割左子树,这样就错了。

    Code:

    #include <iostream>
    #include <cstdio>
    #include <vector>
    using namespace std;
    //Mystery_Sky
    //误人子弟的90分错误贪心
    #define M 1000
    #define INF 0x3f3f3f3f
    #define ll long long
    inline int read()
    {
    	int x=0,f=1; char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    struct Edge{
    	int to, next;
    }edge[M];
    int n, m, tot, max_dep;
    int son[M], dep[M], remain[M], f[M];
    int cnt, head[M];
    
    inline void add_edge(int u, int v)
    {
    	edge[++cnt].to = v;
    	edge[cnt].next = head[u];
    	head[u] = cnt;
    }
    
    void dfs(int p, int fa)
    {
    	if(son[p]) return;
    	son[p] = 1;
    	for(int i = head[p]; i ; i = edge[i].next) {
    		int v = edge[i].to;
    		if(v == fa) continue;
    		dep[v] = dep[p] + 1;
    		max_dep = max(dep[v], max_dep);
    		dfs(v, p);
    		son[p] += son[v];
    		f[v] = p;
    	}
    }
    
    void del(int p)
    {
    	remain[p] = 0;
    	for(int i = head[p]; i; i = edge[i].next) {
    		int v = edge[i].to;
    		if(v == f[p]) continue;
    		del(v);
    	}
    	return;
    }
    
    void dfs_1(int d)
    {
    	if(d > max_dep) return;
    	int pos = 0, Max = 0; 
    	for(int p = 1; p <= n; p++) {
    		if(remain[p] && dep[p] == d) {
    			for(int i = head[p]; i; i = edge[i].next) {
    				int v = edge[i].to;
    				if(v == f[p]) continue;
    				if(son[v] >= Max) pos = v, Max = son[v];
    			}	
    		}
    	}
    	tot += Max;
    	del(pos);
    	dfs_1(d+1);
    }
    
    int main() {
    	n = read(), m = read();
    	for(int i = 1; i <= m; i++) {
    		int u = read(), v = read();
    		add_edge(u, v);
    		add_edge(v, u);
    	}
    	dep[1] = 1;
    	dfs(1, 0);
    	for(int i = 1; i <= n; i++) remain[i] = 1;
    	dfs_1(1);
    	printf("%d
    ", n - tot);
    	return 0;
    }
    

    正解:考完试之后试着往搜索那方面去想了想,然后参考了部分题解,解决了这道题。因为n的范围很小,所以没有必要追求太高的效率,完全可以直接爆搜对吧,连剪枝都可以不用。。。

    Code:

    #include <iostream>
    #include <cstdio>
    #include <vector>
    using namespace std;
    //Mystery_Sky
    //
    #define M 400
    #define INF 0x3f3f3f3f
    #define ll long long
    inline int read()
    {
    	int x=0,f=1; char c=getchar();
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
    
    struct Tree{
    	int fa, son[M], sons, size;
    }tree[M];
    
    int n, m, ans, max_dep;
    int dep[M][M], remain[M], f[M];
    int cnt, head[M];
    
    void dfs(int p, int d)
    {
    	//if(!tree[p].sons) return;
    	max_dep = max(d, max_dep);
    	for(int i = 1; i <= tree[p].sons; i++) {
    		dep[d][0]++;
    		dep[d][dep[d][0]] = tree[p].son[i];
    		dfs(tree[p].son[i], d+1);
    	}
    	return;
    }
    
    int get_size(int p)
    {
    	for(int i = 1; i <= tree[p].sons; i++) {
    		tree[p].size += get_size(tree[p].son[i]);
    	}
    	return tree[p].size;
    }
    
    void del(int p)
    {
    	remain[p] = 0;
    	for(int i = 1; i <= tree[p].sons; i++) {
    		int v = tree[p].son[i];
    		del(v);
    	}
    	return;
    }
    
    void remark(int p)
    {
    	remain[p] = 1;
    	for(int i = 1; i <= tree[p].sons; i++) {
    		int v = tree[p].son[i];
    		remark(v);
    	}
    	return;
    }
    
    void dfs_1(int d, int sum)
    {
    	if(d == max_dep) {
    		ans = max(sum, ans);
    		return;
    	}
    	int s = 0;
    	for(int i = 1; i <= dep[d][0]; i++) {
    		int u = dep[d][i];
    		if(!remain[u]) {
    			s++;
    			continue;
    		}
    		del(u);
    		dfs_1(d+1, sum + tree[u].size);
    		remark(u);
    	}
    	if(s == dep[d][0]) {
    		ans = max(ans, sum);
    	}
    }
    
    int main() {
    	n = read(), m = read();
    	for(int i = 1; i <= n; i++) tree[i].size = 1;
    	for(int i = 1; i <= m; i++) {
    		int u = read(), v = read();
    		if(u > v) swap(u, v);
    		tree[u].son[++tree[u].sons] = v;
    		tree[v].fa = u;
    	}
    	dfs(1, 2);
    	get_size(1);
    	for(int i = 1; i <= n; i++) remain[i] = 1;
    	dfs_1(2, 0);
    	//for(int i = 1; i <= n; i++) printf("%d
    ", tree[i].size); 
    	printf("%d
    ", n - ans);
    	return 0;
    }
    

    总分:100+10+100+90=300

  • 相关阅读:
    Android之针对WebView的全屏播放
    Android之Android WebView常见问题及解决方案汇总
    android之针对fragment多次调用onCreateView的问题
    Android之在string.xml配置文字颜色粗体等效果
    ios成长之每日一遍(day 8)
    Android之TextView灵活使用
    ubuntu忘记root密码 的解决方法
    Mono Touch Table应用
    判断checkbox选中的个数
    C指针原理(14)
  • 原文地址:https://www.cnblogs.com/Benjamin-cpp/p/11721041.html
Copyright © 2011-2022 走看看