最近的vj好垃圾,老崩,实名吐槽
题意:给出一个错误的求最小点覆盖的函数,需要来构造一组样例,使得那个函数跑出来的答案是正解的3倍以上。
很巧妙的构造技巧,首先想法就是弄一个二分图,让正确答案是上面的n个点,我们需要构造的就是下面的点,这就不知道为什么要这样构造了。也就是分块的思想。
从1~n每次分n/i个块,每个块的大小为i,对于每个块下面就构造出一个点跟块里所有点相连。
这样下面的点就是n+n/2+n/3+n/4+...大约就是nlnn个点,那我们要求nlnn>=3n,n>=27就可以了。
正确性上面,下面的点的度数为,1个为n的,n/(n-1)个位n-1的...n个位1的,这样每次都是优先选下面的点。
1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 typedef pair<int,int> pii; 5 vector<pii> vv; 6 int main(){ 7 int u=30,v; 8 for(int i=1;i<=30;i++){ 9 for(int j=0;j<30/i;j++){ 10 u++; 11 for(int k=1;k<=i;k++){ 12 v=i*j+k; 13 vv.push_back(pii(u,v)); 14 } 15 } 16 } 17 printf("%d %d ",u,(int)vv.size()); 18 for(int i=0;i<vv.size();i++) printf("%d %d ",vv[i].first,vv[i].second); 19 printf("30 "); 20 for(int i=1;i<=30;i++) printf("%d ",i); 21 return 0; 22 }
1 #include<cstdio> 2 #include<vector> 3 using namespace std; 4 const int N=10000; 5 int vis[N],deg[N]; 6 vector<int> vv[N]; 7 int f(int n){ 8 int ans=0; 9 while(true){ 10 int mx=-1,u; 11 for(int i=1;i<=n;i++){ 12 if(vis[i]) continue; 13 if(deg[i]>=mx){ 14 mx=deg[i]; 15 u=i; 16 } 17 } 18 if(mx<=0) break; 19 ans++; 20 vis[u]=1; 21 for(int i=0;i<(int)vv[u].size();i++) deg[vv[u][i]]--; 22 } 23 return ans; 24 } 25 int main(){ 26 int n,m,u,v; 27 while(~scanf("%d%d",&n,&m)){ 28 while(m--){ 29 scanf("%d%d",&u,&v); 30 vv[u].push_back(v); 31 vv[v].push_back(u); 32 deg[u]++; 33 deg[v]++; 34 } 35 //for(int i=1;i<=30;i++) printf("%d ",deg[i]); 36 printf("%d ",f(n)); 37 } 38 return 0; 39 }