题目链接:sicily 1140
解题思路:贪心+深搜
相当考编程能力的一道题,一个手贱就卡了好几天,不过的确是一到好题。考察的是对贪心法的运用,还有编程能力——深搜。贪心原则是从最小结点开始搜索(这样最小结点就是根结点),然后对于每一个结点,搜索返回结点数和最小结点,根据题意比较结果,每次贪心搜索之后删除那条边,并标记整个子图,再继续搜索,直到所有的人都分到遗产。
代码:(有可能冗余很多,但都是测试需要)
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int n,m,cnt,start,end,ans,minx,index_;
int v[30005],sign[30005];
vector<int> vec[30005];
pair<int,int> dfs(int index)
{
int sum=1,len=vec[index].size(),tmp,tmp_min=index;
for(int i=0;i<len;i++)
{
if(vec[index][i]&&!sign[vec[index][i]]&&!v[vec[index][i]])
{
v[vec[index][i]]=1;
pair<int,int> new_pair=dfs(vec[index][i]);
// cout<<vec[index][i]<<endl;
tmp=new_pair.first;
sum+=tmp;
int tmp1=cnt-tmp,tmp2=tmp;
if(tmp1<=tmp2)
{
if(tmp1>ans)
{
// cout<<"case1111111111"<<endl;
ans=tmp1,minx=index_;
start=index,end=vec[index][i];
}
else if(tmp1==ans&&minx>index_)
{
// cout<<"case2222222222"<<endl;
minx=index_;
start=index,end=vec[index][i];
}
}
else
{
if(tmp2>ans)
{
// cout<<"case3333333333"<<endl;
ans=tmp2,minx=new_pair.second;
start=index,end=vec[index][i];
}
else if(tmp2==ans&&minx>new_pair.second)
{
// cout<<"case4444444444"<<endl;
minx=new_pair.second;
start=index,end=vec[index][i];
}
}
tmp_min=min(tmp_min,new_pair.second);
}
}
// cout<<"dfs: "<<sum<<" index: "<<index<<" minx: "<<minx<<endl;
// cout<<start<<" & "<<end<<endl;
return make_pair(sum,tmp_min);
}
void remove(int index)
{
int len=vec[index].size();
for(int i=0;i<len;i++)
if(vec[index][i]&&!sign[vec[index][i]])
sign[vec[index][i]]=1,remove(vec[index][i]);
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
memset(sign,0,sizeof(sign));
memset(vec,0,sizeof(vec));
int x,y;
for(int i=1;i<n;i++)
{
scanf("%d %d",&x,&y);
vec[x].push_back(y);
vec[y].push_back(x);
}
cnt=n,start=-1,end=-1,sign[0]=1;
for(int i=1;i<m;i++)
{
if(cnt==1)
{
printf("0 ");
continue;
}
memset(v,0,sizeof(v));
ans=0,index_=-1,minx=INF;
for(int j=1;j<=n;j++)
if(!sign[j]){
index_=j;
break;
}
v[index_]=1;
int num=dfs(index_).second;
// cout<<i<<": "<<index_<<endl;
// cout<<"num: "<<num<<endl;
// cout<<"!!!!!!!!!!!: "<<start<<" & "<<end<<endl;
int len=vec[start].size();
for(int i=0;i<len;i++)
if(vec[start][i]==end)
{
vec[start][i]=0;
break;
}
len=vec[end].size();
for(int i=0;i<len;i++)
if(vec[end][i]==start)
{
vec[end][i]=0;
break;
}
sign[minx]=1;
remove(minx);
printf("%d ",ans);
cnt-=ans;
}
printf("%d\n",cnt);
}
return 0;
}
总结:
1、突然觉得,最难的算法是贪心!
2、回溯法的一个例子原来就是深搜?!(之前一直不知道回溯法是啥……)
时间: 2024-10-12 02:05:44