sicily 1140(搜索)

题目链接: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、回溯法的一个例子原来就是深搜?!(之前一直不知道回溯法是啥……)

你可能感兴趣的:(sicily 1140(搜索))