Gym - 101597D-搜索&思维&推结论-Effective network

58 篇文章 0 订阅

http://codeforces.com/gym/101597/problem/D
这种搜索不像是普通的搜索,更像是一种思维题。
并且题目有一个暗示:
输出的集合只要满足条件就行,没有说最大还是最小。


给定一个图,要求你求一个集合。
x(集合里的数)-k(大小)>=(集合中任意点最短距离的最大距离)
要求你输出这个集合。
集合中最小的为2。
我开的思路是对每个点bfs。然后记录他们各个层数的点的数目,然后求一下前缀,
就用该前缀x-k >=j,然后我们就可以输出
但是再处理样例的时候,我发现每两个层次为j的点距离为2。
然后就wa了。
因为两个层次为j的点距离可能并不为2*j,因为他们俩可能直接相连(这是我后来看的数据)
正解:对每个点bfs。然后保存每个点的层数值,维护一个最大值。可以保证如果 所有的点 n-k>=max,那么其他就成立,输出1-n.否则就不可以。
简易的证明:
如果对于x个点(x<=n) 存在x-k>=max, 那么x增加一个点。最多到最max+1。那么 (x+1)-k>=(max+1) 依然成立。所以增加到n也是成立的。并且再实际情况中 max并不一定会增加1。这时考虑最差的情况。


2018.5.10:刚才看了一下vj,这道题上交的题的写法都是这样…… 好开心
这里写图片描述
简易的证明:若对于部分区域该条件成立(设内部点位x个,路长度限制为k,内部最长路为lens)。满足x-k>=(lens)。
则一个点向外延伸一圈,x最少增加1(事实,因为这是一个连通图),而lens也增加1. 则条件会更成立。所以可以扩展到全图。
直接求树的直径也是很好的。

#include <bits/stdc++.h>
using namespace std;
const int maxn=5005;
vector<int>G[maxn];
vector<int>num[maxn];
int d[maxn];
bool vis[maxn];
int m;
int bfs(int x){
   for(int i=0;i<maxn;i++)
       num[i].clear();
   queue< pair<int,int> >q;
   memset(vis,false,sizeof(vis));
   memset(d,0,sizeof(d));
   vis[x]=true;
   d[x]=0;
   q.push(make_pair(x,0));
   while(!q.empty()){
       pair<int,int>u=q.front();
       q.pop();
       d[u.first]=u.second;
       for(int i=0;i<G[u.first].size();i++){
          int to=G[u.first][i];
          if(!vis[to]){
             vis[to]=true;
             q.push(make_pair(to,u.second+1));
          }
       }
   }
   int ans=-1;
   for(int i=1;i<=m;i++){
     ans=max(d[i],ans);
   }
return ans;
}
int main()
{   int n,k,a,b;
     scanf("%d%d%d",&m,&n,&k);
     for(int i=0;i<n;i++){
         scanf("%d%d",&a,&b);
         G[a].push_back(b);
         G[b].push_back(a);
     }
     int rel=-1;
     for(int i=1;i<=m;i++){
         rel=max(bfs(i),rel);

     }
     if(rel<=m-k){
        printf("%d\n",m);
             for(int j=1;j<=m;j++){
                  if(j==1)
                  printf("%d",j);
                  else
                  printf(" %d",j);
            }
        cout<<endl;
     }
     else{
        puts("0");
     }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值