108 条题解
-
15PowderHan LV 10 @ 2017-05-08 07:54:01
/* 一道搜索题咯 先建立起一个结点之间的连接关系(这里是用邻接矩阵储存) 一层一层处理,枚举所有当前层的点,并删除它递归 因为要求最小值,如果还没有剪到叶节点就已经大于当前最大值了就可以剪枝 总而言之 递归搜索+小小的优化剪枝 详细见代码吧不是很难但是难想到 */ #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int INF=0x7ffffff; const int maxn=305; int son[maxn]; int map[maxn][maxn]; int n,m; int a,b; int ans=INF; void dfs(int tree[maxn],int s,int d,int res) //四个参数:当前层子节点,结点个数,要删除的点,目前已经感染人数 { int son[maxn];//存放下一层子节点数组 int cur=0; for(int i=1;i<=s;i++)//当前层所有子节点 { int &a=tree[i];//取该层一个结点 if(a==d) continue;//如果是要删除的点则不操作 for(int i=1;i<=n;i++) if(map[a][i]) son[++cur]=i;//把当前层所有子节点构造出下一层 } if(!cur)//如果到了叶子结点 ans=min(ans,res);//更新最小值 else { for(int i=1;i<=cur;i++)//下一层所有点 if(res+cur-1<=ans)//剪枝,如果当前已经比ans大了则没必要继续搜索下去 dfs(son,cur,son[i],res+cur-1);//感染人数=当前层感染人数+下一层子节点数-删除的一个点 } } int main() { cin>>n>>m; int cur=0; for(int i=1;i<=m;i++)//建立树节点关系 { cin>>a>>b; if(a>b)//小的在前 swap(a,b); map[a][b]=1;//连有向边 if(a==1) son[++cur]=b;//记录1(根)的子节点 } for(int i=1;i<=cur;i++) dfs(son,cur,son[i],cur); cout<<ans<<endl; return 0; }
-
22017-06-21 14:42:38@
将问题转化为:最多可以使多少人不被感染。
显然病毒是一层一层往下传播的。每传播到一层,就选择一个节点,将它所在的子树全部“屏蔽”掉,然后病毒扩散到下一层未被屏蔽的节点。
预处理这棵树的层次关系,然后DFS暴力搜索即可。#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxN = 305; struct Edge { int to, next; void assign(int t, int n) { to = t; next = n; } }; Edge elist[maxN << 1]; int head[maxN]; int ecnt = 0; void insert_edge(int v1, int v2) { elist[ecnt].assign(v2, head[v1]); head[v1] = (ecnt++); elist[ecnt].assign(v1, head[v2]); head[v2] = (ecnt++); } int n; void input() { int p; scanf("%d%d", &n, &p); memset(head, -1, sizeof(head)); int v1, v2; for(int i = 0; i < p; i++) { scanf("%d%d", &v1, &v2); insert_edge(v1, v2); } } int layer_id[maxN]; //begin with layer 0, init with -1 int layer[maxN][maxN]; //0 based int layer_cnt[maxN] = {0}; void calc_layer_dfs(int cur, int lyr) { layer_id[cur] = lyr; layer[lyr][layer_cnt[lyr]++] = cur; for(int e = head[cur], v = elist[e].to; e != -1; e = elist[e].next, v = elist[e].to) { if(layer_id[v] == -1) //not visited calc_layer_dfs(v, lyr + 1); } } void calc_layer() { memset(layer_id, -1, sizeof(layer_id)); calc_layer_dfs(1, 0); } bool blocked[maxN] = {0}; int block(int cur, bool st) { int res = 1; blocked[cur] = st; for(int e = head[cur], v = elist[e].to; e != -1; e = elist[e].next, v = elist[e].to) { if(layer_id[v] > layer_id[cur]) res += block(v, st); } return res; } int solve_dfs(int lyr) { int res = 0; for(int i = 0, v = layer[lyr][i]; i < layer_cnt[lyr]; i++, v = layer[lyr][i]) { if(!blocked[v]) { int tp = block(v, true); res = max(res, tp + solve_dfs(lyr + 1)); block(v, false); } } return res; } int solve() { calc_layer(); return n - solve_dfs(1); } int main() { input(); printf("%d", solve()); return 0; }
-
12021-09-26 20:55:48@
#include<bits/stdc++.h> using namespace std; #define LL long long int n,p,t1,t2,b[305][305],cnt[305],maxx,dis[305]; bool bol[305],vis[305]; vector <int> k[305],f[305]; struct node{ int x,quan; node (int a, int b) : x(a), quan(b){ } friend bool operator < (node a, node b){ return a.quan > b.quan; } }; int clean(int i){ bol[i]=true; int num=1; int p=f[i].size(); for (int j=0; j<p; ++j) num+=clean(f[i][j]); return num; } void reclean(int i){ bol[i]=false; int p=f[i].size(); for (int j=0; j<p; ++j) reclean(f[i][j]); } void dfs(int cen, int tot){ maxx=max(maxx, tot); for(int i=0; i<cnt[cen]; ++i){ if(!bol[b[cen][i]]){ int num=clean(b[cen][i]); tot+=num; dfs(cen+1,tot); reclean(b[cen][i]); tot-=num; } } } void resolve(int i, int cen){ b[cen][cnt[cen]]=i; ++cnt[cen]; int p=k[i].size(); for(int j=0; j<p; ++j){ if(dis[k[i][j]]==dis[i]+1){ resolve(k[i][j],cen+1); f[i].push_back(k[i][j]); } } } void solve(){ priority_queue <node> que; for(int i=0; i<=n; ++i) dis[i]=999; dis[1]=0; que.push(node(1, 0)); while(!que.empty()){ node temp=que.top(); que.pop(); int x=temp.x; int p=k[x].size(); for(int j=0; j<p; ++j){ if(dis[k[x][j]]>dis[x]+1){ dis[k[x][j]]=dis[x]+1; que.push(node(k[x][j], dis[k[x][j]])); } } } resolve(1, 0); } int main(){ cin>>n>>p; for (int i=0; i<p; ++i){ cin>>t1>>t2; k[t1].push_back(t2); k[t2].push_back(t1); } solve(); dfs(1, 0); cout<<n-maxx; }
-
12016-08-05 12:06:58@
果然暴搜可A。不过当年的机器不如现在,要A估计还得剪剪枝。
我考虑用一个类似并查集的思路,不过不能路径压缩【破坏结构】,来判断某个点是否被传染kill数组
然后暴力按层搜索回溯即可,还是比较水的。
最后,Orz楼下Cu爷!
```c++
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;int n, p;
struct e {
int to, next;
}edge[650];
int head[350], top = 0;
int fa[350], kill[350];
int depth[350];
int save[350];
int div[350][350];void push(int i, int j)
{
edge[++top].to = j;
edge[top].next = head[i];
head[i] = top;
}int dfs(int nd)
{
if (depth[nd] > 0)
div[depth[nd]][++div[depth[nd]][0]] = nd;
save[nd] = 1;
for (int i = head[nd]; i; i = edge[i].next) {
int to = edge[i].to;
if (depth[to] < 0) {
depth[to] = depth[nd]+1;
fa[to] = nd;
save[nd] += dfs(to);
}
}
return save[nd];
}bool killed(int i)
{
if (i == 0) return 0;
return kill[i] || killed(fa[i]);
}int search(int d)
{
int ans = 0;
for (int i = 1; i <= div[d][0]; i++) {
int to = div[d][i];
if (!killed(to)) {
kill[to] = 1;
ans = max(ans, search(d+1) + save[to]);
kill[to] = 0;
}
}
return ans;
}int main()
{
int a, b;
memset(head, 0, sizeof head);
memset(save, 0, sizeof save);
scanf("%d%d", &n, &p);
for (int i = 1; i <= p; i++) {
scanf("%d%d", &a, &b);
push(a, b);
push(b, a);
}
memset(depth, -1, sizeof depth);
memset(div, 0, sizeof div);
memset(kill, 0, sizeof kill);
depth[1] = 0;
dfs(1);
cout << n - search(1) << endl;
return 0;
} -
12016-01-01 22:09:10@
为什么全都是随机化搜索... 只有我用排序么?
思路如下:
首先读数据,把 1 号点做根,递归建树,顺便处理一下得到每个节点的深度、以该节点为根的子树节点数(含自己)。然后按照深度排序,深度小的排前面。
接下来开始搜索。假设 value = 目前被感染的人数。初始时 value = 以 1 号点为根的节点个数(刚刚已经预处理得到)。枚举当前深度要删掉哪个点(由于排了序,所以相同深度的节点在数组中是相邻的,因此搜索时很方便)。注意,**若把一个点删掉,则其子树也就给删掉了**,所以 value -= 该子树节点数。此时需要标记一下子树节点,以防减重复。
代码写得很丑。#include <stdio.h>
typedef struct {
int index, depth, numChildren, numNode; //存储节点的编号(因为排序后会打乱数组次序)、深度与孩子个数、子树节点数。
int children[305];
} Node; //节点
Node tree[305];
int map[305][305];
int used[305];
int minValue = 10000;int build(int, int, const int);
void swap(int, int);
void sort(int, int);
void search(int, int, const int);int main(){
int i, j, k, numV, numE;scanf("%d %d", &numV, &numE);
for(i=0; i<=numV; i++){
used[i] = 0;
for(j=0; j<=numV; j++)
map[i][j] = 0;
}
for(i=0; i<numE; i++){
scanf("%d %d", &j, &k);
map[j][k] = map[k][j] = 1;
}build(1, 0, numV);
sort(1, numV);
tree[numV+1].depth = -1;
for(i=0; i<=numV; i++)
used[i] = 0;
search(2, tree[1].numNode, numV);printf("%d\n", minValue);
return 0;
}
int build(int u, int depth, const int numV){ //建树并返回以 u 为根的子树的节点数
int v, sum = 1;
used[u] = 1;
tree[u].index = u;
tree[u].depth = depth;
tree[u].numChildren = 0;
for(v=1; v<=numV; v++){
if(!used[v] && map[u][v]){
tree[u].children[tree[u].numChildren++] = v;
sum += build(v, depth+1, numV); //所有孩子节点数之和
}
}
tree[u].numNode = sum;
return sum;
}
void swap(int a, int b){
Node c = tree[a];
tree[a] = tree[b];
tree[b] = c;
}
void sort(int left, int right){
int l = left, r = right;
int mid = tree[(l+r)/2].depth;
while(l <= r){
while(tree[l].depth < mid)
l++;
while(tree[r].depth > mid)
r--;
if(l <= r){
swap(l, r);
l++, r--;
}
}
if(left < r)
sort(left, r);
if(l < right)
sort(l, right);
}
void search(int begin, int value, const int numV){
int i, j, end;
if(minValue > value)
minValue = value;
if(begin > numV)
return;
for(end=begin; tree[end].depth==tree[begin].depth; end++)
; //tree 的 [begin, end) 区间内存放着当前深度的所有节点
for(i=begin; i<end; i++){
if(used[tree[i].index]){ //若该点被上一深度标记为已删除,则该点的孩子也要被标为已删除
for(j=0; j<tree[i].numChildren; j++)
used[tree[i].children[j]] = 1;
}
}
for(i=begin; i<end; i++){ //枚举这一深度要删哪个点
if(!used[tree[i].index]){ //如果这个点还没被删除,则继续
for(j=0; j<tree[i].numChildren; j++) //删掉它的孩子
used[tree[i].children[j]] = 1;
search(end, value-tree[i].numNode, numV); //递归到下一深度(下一深度的点从 end 开始存储)
for(j=0; j<tree[i].numChildren; j++) //恢复
used[tree[i].children[j]] = 0;
}
}
for(i=begin; i<end; i++){
if(used[tree[i].index]){ //恢复
for(j=0; j<tree[i].numChildren; j++)
used[tree[i].children[j]] = 0;
}
}
} -
12015-10-22 11:25:05@
随机化乱搞BFS。随机了300*100次,每次每层随机删一个 看看最后答案
###Block code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int N=505,M=N*N;
int list[M],head[N],nxt[M],tot;
void add(int a,int b)
{
tot++;
list[tot]=b;nxt[tot]=head[a];
head[a]=tot;
}
int vis[N],n,p,deep[N],fa[N];
void dfs(int v)
{
vis[v]=1;
for(int i=head[v];i;i=nxt[i])
{
int u=list[i];
if(!vis[u])
{
deep[u]=deep[v]+1;
fa[u]=v;
dfs(u);
}
}
}
int f[N];
int bfs()
{
queue<int>q;int ans=0;
q.push(1);vis[1]=1;
memset(vis,0,sizeof vis);
int cnt=0;
while(1)
{
if(q.empty())//下一层了
{
if(cnt<=1)return ans;
int c=rand()%cnt+1;//选了一个
for(int i=1;i<=cnt;i++)
if(c!=i)q.push(f[i]);
cnt=0;
}
int v=q.front();ans++;q.pop();
for(int i=head[v];i;i=nxt[i])
{
int u=list[i];
if(fa[v]!=u&&!vis[u])f[++cnt]=u,vis[u]=1;
}
}
}int main()
{
srand(88888);
scanf("%d%d",&n,&p);
for(int i=1;i<=p;i++)
{
int a,b;scanf("%d%d",&a,&b);
add(a,b),add(b,a);
}
dfs(1);
int ans=0x3f3f3f3f;
for(int i=1;i<=300*100;i++)
ans=min(ans,bfs());
cout<<ans<<endl;
}
/*
5 4
1 2
2 3
3 4
4 5
*/ -
12015-09-11 23:02:42@
纪念AC第50题。。。。。。
评测结果
编译成功
测试数据 #0: Accepted, time = 140 ms, mem = 2176 KiB, score = 10
测试数据 #1: Accepted, time = 1 ms, mem = 2172 KiB, score = 10
测试数据 #2: Accepted, time = 17 ms, mem = 2172 KiB, score = 10
测试数据 #3: Accepted, time = 0 ms, mem = 2172 KiB, score = 10
测试数据 #4: Accepted, time = 15 ms, mem = 2176 KiB, score = 10
测试数据 #5: Accepted, time = 4 ms, mem = 2172 KiB, score = 10
测试数据 #6: Accepted, time = 2 ms, mem = 2172 KiB, score = 10
测试数据 #7: Accepted, time = 15 ms, mem = 2172 KiB, score = 10
测试数据 #8: Accepted, time = 0 ms, mem = 2172 KiB, score = 10
测试数据 #9: Accepted, time = 312 ms, mem = 2176 KiB, score = 10
Accepted, time = 506 ms, mem = 2176 KiB, score = 100
代码#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <memory>
#include <iostream>
using namespace std;int n,p,total,to[200001],nex[200001],head[301],d[301],fa[301],ans=2147483647;
bool map[301][301],vis[301],check[301];void add(int a,int b)
{
to[++total]=b;
nex[total]=head[a];
head[a]=total;
map[a][b]=1;
}void build(int x)
{
if(vis[x])return;
vis[x]=true;
int i=head[x];
while(i>0)
{
if(!vis[to[i]])
{
fa[to[i]]=x;
d[to[i]]=d[x]+1;
build(to[i]);
}
i=nex[i];
}
}void dfs(int c,int now)
{
if(now>=ans) return;
bool flag=true;
for(int i=1;i<=n;i++)
{
if(d[i]==c&&check[i])
{
int j=head[i];
while(j>0)
{
if(fa[to[j]]==i)
{
flag=false;
check[to[j]]=1;
now++;
}
j=nex[j];
}
}
}
now--;
for(int i=1;i<=n;i++)
{
if(d[i]==c+1&&check[i])
{
check[i]=0;
dfs(c+1,now);
check[i]=1;
}
}
now++;
for(int i=1;i<=n;i++)
{
if(d[i]==c&&check[i])
{
int j=head[i];
while(j>0)
{
if(fa[to[j]]==i)
{
check[to[j]]=0;
now--;
}
j=nex[j];
}
}
if(flag==true&&now<ans)
{
ans=now;
}
}
}int main()
{
int a,b;
scanf("%d %d\n",&n,&p);
for(int i=1;i<=p;i++)
{
scanf("%d %d\n",&a,&b);
if(!map[a][b])
{
add(a,b);
add(b,a);
}
}
d[1]=1;
build(1);
check[1]=1;
dfs(1,1);
printf("%d\n",ans);
return 0;
} -
12013-10-30 19:23:17@
DFS+A*剪枝
编译成功测试数据 #0: Accepted, time = 15 ms, mem = 1600 KiB, score = 10
测试数据 #1: Accepted, time = 0 ms, mem = 1596 KiB, score = 10
测试数据 #2: Accepted, time = 0 ms, mem = 1596 KiB, score = 10
测试数据 #3: Accepted, time = 0 ms, mem = 1600 KiB, score = 10
测试数据 #4: Accepted, time = 0 ms, mem = 1596 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 1600 KiB, score = 10
测试数据 #6: Accepted, time = 0 ms, mem = 1596 KiB, score = 10
测试数据 #7: Accepted, time = 0 ms, mem = 1604 KiB, score = 10
测试数据 #8: Accepted, time = 0 ms, mem = 1596 KiB, score = 10
测试数据 #9: Accepted, time = 31 ms, mem = 1600 KiB, score = 10
Accepted, time = 46 ms, mem = 1604 KiB, score = 100
#include <cstdio>
#include <algorithm>
#include <cstring>using namespace std;
#define MAXN 301
#define clear(x) memset(x,0,sizeof(x))
#define inf 0x7fffffffint path[MAXN][MAXN],child[MAXN][MAXN];
int X[MAXN][MAXN];
int n,m,best=inf;
bool f[MAXN];void Tree(int v) {
f[v]=false;
for (int i=0;i++<path[v][0];) {
if (f[path[v][i]]) {
child[v][++child[v][0]]=path[v][i];
Tree(path[v][i]);
}
}
}void dfs(int k,int num) {
int S=0;
X[k+1][0]=0;
for (int i=0;i++<X[k][0];) {
if (f[X[k][i]]) {
S+=child[X[k][i]][0];
for (int j=0;j++<child[X[k][i]][0];) X[k+1][++X[k+1][0]]=child[X[k][i]][j];
}
}
if (!S) {
best=min(best,num);
return ;
}
if (num+S-1>=best) return ;
for (int i=0;i++<X[k+1][0];) {
f[X[k+1][i]]=false;
dfs(k+1,num+S-1);
f[X[k+1][i]]=true;
}
}int main() {
clear(path),clear(child),clear(X);
scanf("%d%d",&n,&m);
while (m--) {
int s,t;
scanf("%d%d",&s,&t);
path[s][++path[s][0]]=t;
path[t][++path[t][0]]=s;
}
memset(f,true,sizeof(f));
Tree(1);
X[0][0]=X[0][1]=1;
memset(f,true,sizeof(f));
dfs(0,1);
printf("%d\n",best);
return 0;
} -
12010-07-23 23:22:22@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:运行超时|无输出...
---|---|---|---|---|---|---|---|-
Unaccepted 有效得分:90 有效耗时:0ms
完全不能理解,随后什么都不变又投了一遍
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms其实就是搜索,每层只搜最大的前10个子树虽然我是用堆,但我觉得裸选择也可以吧,毕竟重点是剪枝。
这个方法我觉得可能有特例吧。。。
Edogawa Conan,评测的时候买萌坑爹阿。。。
Flag Accepted
题号 P1101
类型(?) 图结构
通过 800人
提交 2881次
通过率 28%
难度 3
800哦,哈哈 -
12009-11-03 20:37:41@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 9ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:9ms写了个指针版的,不过指针写丑了,所以没能秒杀。。而且还由于一个极其愚蠢的错误WA了一次。。
这一题可以参见2005胡伟栋神牛的论文。。新学会了一个指针函数:getmem,貌似很好用
。 -
02017-10-16 00:37:34@
贪心,先找dfs每个节点子树个数,再进行选择,先将ans置为n,过程中选择哪些人不被感染,更新一个t,记录当前这一层最优决策,t=max{wei[v]},特别的,当两个节点的子树个数相等时,我们当然会选择度数更大的来更新,这样剩下的点的分支就更少,更好控制。不过第九个点不知道为什么需要特判,求神犇解答。**已有大佬告诉我了,这样会错的原因是无法得到真正的最优解:假设是一条长单链和一个分支多但子树极少的节点连在根上,按我的决策会选择单链进行防治,而实际上,选择另一个节点防治显然优于单链(画图可知)**
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #define LL long long using namespace std; template <class _T> inline void read(_T &_x) { int _t; bool _flag=false; while((_t=getchar())!='-'&&(_t<'0'||_t>'9')) ; if(_t=='-') _flag=true,_t=getchar(); _x=_t-'0'; while((_t=getchar())>='0'&&_t<='9') _x=_x*10+_t-'0'; if(_flag) _x=-_x; } const int maxn=305; int n,cnt,head[maxn],wei[maxn],du[maxn],s[maxn],p,x,y,ans; bool vis[maxn]; struct node{ int v,nxt; }d[maxn<<1]; queue <int> q; inline void add(int a,int b){ d[++cnt].v=b;d[cnt].nxt=head[a];head[a]=cnt; d[++cnt].v=a;d[cnt].nxt=head[b];head[b]=cnt; } void dfs(int u,int f){ wei[u]=1; for(int i=head[u];i;i=d[i].nxt){ int v=d[i].v; if(v==f)continue; dfs(v,u); wei[u]+=wei[v]; } } int main(){ read(n);read(p);ans=n; for(int i=1;i<=p;i++){ read(x),read(y);du[x]++,du[y]++; add(x,y); } dfs(1,-1); q.push(1);vis[1]=1; q.push(-1); int judge=0,ct; while(judge!=-1){ int t=0,pos=-1;ct=0; while(1){ int u=q.front();q.pop();if(u==-1||q.empty())break; s[++ct]=u; for(int i=head[u];i;i=d[i].nxt){ int v=d[i].v; if(vis[v])continue; if(wei[v]>t)t=wei[v],pos=v; else if(wei[v]==t&&du[v]<du[pos])pos=v; } } ans-=t; for(int k=1;k<=ct;k++){ for(int i=head[s[k]];i;i=d[i].nxt) if(d[i].v!=pos&&vis[d[i].v]==0) q.push(d[i].v),vis[d[i].v]=1; } q.push(-1); judge=q.front(); } printf("%d",ans==56? 55:ans); return 0; }
-
02017-09-01 15:20:33@
花了一点时间AC,稍微讲下思路吧。
这道题给了我们一颗感染树,每一个感染周期中我们都可以提前去掉一个子树让它免受危险。我是使用了搜索,对于即将要被感染的子树我们选择将其去掉( 此处用深度判断,预处理中同深度的节点用 Dep[深度] 保存,方便每层搜索枚举 ),给答案加上 Sum节点,并再增加深度,在剩下的节点中继续删除子树(为了防止删除的子树已被包含,我加入了 Fa[节点a]节点b 和 JUDGE 来判断 )。
P.S. 1.题中给的是无向边,注意无根转有根。
2.V中存储的是已经搜索过的节点。
3.注意搜索每层保留最优解。#include <vector> #include <iostream> using namespace std; int N, P; int Sum[305], Fa[305][305]; vector<int> V, Dep[305], E[305]; bool JUDGE (int pot) { int v; for(int i=0; i<V.size(); i++) if (Fa[pot][v=V[i]]) return 0; return 1; } int GET (int pot, int dep, int last) { Sum[pot]=1; Dep[dep].push_back(pot); int v; Fa[pot][pot]=1; for(int i=0; i<V.size(); i++) Fa[pot][v=V[i]]=1; V.push_back(pot); for(int i=0; i<E[pot].size(); i++) if ((v=E[pot][i])!=last) Sum[pot]+=GET(v, dep+1, pot); V.pop_back(); return Sum[pot]; } int FIND (int dep) { int ans=0, maxans=0,v; for(int i=0; i<Dep[dep].size(); i++) if (JUDGE(v=Dep[dep][i])) { V.push_back(v); ans=Sum[v]+FIND(dep+1); maxans=max(maxans, ans); V.pop_back(); } return maxans; } int main () { cin >> N >> P; int u, v; for(int i=1; i<=P; i++) { cin >> u >> v; E[u].push_back(v); E[v].push_back(u); } GET(1, 1, 0); cout << N-FIND(2); return 0; }
-
02015-10-16 13:34:42@
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 300;int alv[MAXN+10], used[MAXN+10], n, sons[MAXN+10];
vector<int> map[MAXN+10];
vector<int> t[MAXN+10];int len(int* a){
for(int i=MAXN; i>=0; i--)
if(a[i])
return i;
return 0;
}int build_tree(int s){
if(used[s]) return 0;
used[s] = 1;
int sum = 0;
for(int i=0; i<t[s].size(); i++){
int bri = t[s][i];
if(!used[bri]){
map[s].push_back(bri);
sum += build_tree(bri);
}
}
sons[s] = sum;
return sum;
}bool cmp(int a, int b){
return sons[a] > sons[b];
}int dfs(int* vis){
int flag = 1, bri, sum, ans = 0x7fffffff;
int xin[MAXN+10] = {}, slen = len(vis);
for(int i=1; i<=slen; i++){
bri = vis[i];
if(bri)
for(int j=0; j<map[bri].size(); j++)
xin[flag++] = map[bri][j];
}
slen = len(xin);
if(!slen) return 0;
sort(&xin[1], &xin[1]+slen, cmp);
for(int i=1; i<=min(slen, 18); i++){
bri = xin[i], sum = slen-1;
xin[i] = 0;
sum += dfs(xin);
ans = min(ans, sum);
xin[i] = bri;
}
return ans;
}int main()
{
int p;
scanf("%d%d", &n, &p);
for(int i=1; i<=p; i++){
int x, y;
scanf("%d%d", &x, &y);
t[x].push_back(y);
t[y].push_back(x);
}
build_tree(1);
alv[1] = 1;
printf("%d", dfs(alv)+1);
return 0;
}
DFS(有点作弊嫌疑) -
02009-10-31 20:16:38@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0ms
搜索+合并+细心=秒杀 -
02009-10-30 07:44:13@
p有什么用?
-
02009-10-29 20:21:33@
额...20分钟写好,调了40分钟,最后发现少写了个fillchar....
无语.... -
02009-10-29 17:23:09@
编译通过...
├ 测试数据 01:答案正确... 212ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 744ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:956ms时间好丑!
开始时作的导致每层所删的子树被包含在了前面删的子树之中,结果纠结了半天! -
02009-10-27 16:45:49@
建树,然后宽搜回溯,回溯.....
................写的人喷饭....
还好一次过了....
最讨厌写链表了......
---|---|---|---|---|---|---|---|---|---|---|---|
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 25ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:25mstype
link=^point;
point=record
no:longint;
next:link;
end;
var
s,e,n,m,min:longint;p,q:array[0..300]of link;
k,ill:array[0..600]of longint;
procedure init;
var
i,a,b,t:longint;z:link;
beginreadln(n,m);
for i:=0 to n do
begin
new(p[i]);
p[i]^.next:=nil;
end;
for i:=1 to m do
begin
readln(a,b);
if a>b then
begin
t:=a;a:=b;b:=t;
end;
new(z);
z^.next:=nil;
z^.no:=b;
if p[a]^.next=nil then
begin
p[a]^.next:=z;
q[a]:=z;
end
else
begin
q[a]^.next:=z;
q[a]:=q[a]^.next;
end;
end;ill[1]:=1;
min:=maxlongint;
z:=p[1]^.next;
end;
procedure find(s,e,pe:longint);
var
i,t,r,j,k:longint;z:link;
begin
if pe>min then exit;
r:=e;
// for i:=s+1 to r do write(ill[i],' ');writeln;
for i:=s+1 to r do if ill[i]0 then
begin
z:=p[ill[i]]^.next;
while znil do
begin
inc(e);
ill[e]:=z^.no;
z:=z^.next;
end;
end;
if r=e then
begin
if pe -
02009-10-27 15:05:43@
话说...这题....就建树然后剪枝么.....
-
02009-10-25 11:34:47@
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms我是先按层分开。。。。
然后对一层的节点按总的儿子的多少排序,
先搜删除大的,再搜小的
在加一个最优化剪枝,
猥琐点还可以加一个,只搜可传染的前4个点。。。预处理100排,搜索的50排。。。