Luogu P1171 售货员的难题

5 篇文章 0 订阅
2 篇文章 0 订阅
Luogu P1171 售货员的难题

这是一道很悲伤的搜索题。。。
充分体现我多么菜。。。
为什么会开始做这道题。。。因为对面的(新招的初二的)刷caioj刷到这一题了
当我在luogu找到后一看是蓝题好慌啊qwq,他们已经这么强了吗。。
不过luogu的数据加强了,lhy和我说caioj上的只要暴搜什么优化不加就可以(大概就是这里的40分的超级裸的暴搜橙题的样子)
于是我觉得要目标远大一点,所以我决定要A掉luogu这里的
5.16中午
打了一中午才20.。。
明明是傻逼题啊。。。
。。。都怪今天头疼(其实是自己弱)
5.17中午
发现 昨天的思路有BUG于是重构
40还有BUG 。。。
我的40好像还不太一样是因为思路错了。。。
重构终于80了
我好菜啊,这么简单,我为什么绕了那么久。。。
5.18中午
还得剪枝优化。。。
容易想到一个似乎不太可行的方法,排序,按边排
打了,结果十分可行啊90了QWQ
还有最后一点啊。。。
5.19晚上
(本来今天上luogu是来月赛的,结果发现我记错时间已经开始1h了,
然后又发现月赛502了于是想想还不如来A这道题吧)
想到lhy周五和我说的,卡常
于是我开始看卡常技巧的blog,把我所有觉得可行的都堆了上去。。。
卡来卡去差不多啊!!
90还是90!!
无可奈何花落去,我点开了一篇题解,我发现思路和我一样(我怎么就A不了!!。。。)
但它多了一个向外连最小的边的数组,如果这条边都不行就都不行,以及先建边再直接排序
于是我把把先暂时储存排序后建边改成先建边再直接排序
最小边那个也依葫芦画瓢打上了(仔细想想并没有用啊,因为已经排序了)
还是90!!
怎么办呐。。。
我点开了luogu的题解
!!!!!!!!!!!我要把这个标的比标题还要大

if(sum+(n-t)+1>=ans)return 0;

就是这个优化,本来我第三个点T了,是1.5s左右的
然后加了这句第三个点0ms,心情复杂。。。

长长的 卡常和调试。。。

#include<cstdio>
#include<cstring>

int n,ans,b[110],c[110][110],road[1010],len,lenn,first[10100],s[10100],z,minn[110];
struct nod1{int x,y,c,next;}a[10010],d[10010];

inline void read(int &x)
{
    register int f=1;
    x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

inline void print(int x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
        print(x/10);
    putchar(x%10+'0');
}

inline int kp(int l,int r)
{
    register int x=l,y=r,m=a[(x+y)/2].c;
    while(x<=y)
    {
        while(a[x].c<m)x++;
        while(a[y].c>m)y--;
        if(x<=y)
        {
            nod1 t=a[x];a[x]=a[y];a[y]=t;
            x++;y--;
        }
    }
    if(l<y)kp(l,y);
    if(x<r)kp(x,r);
}

/*inline int ins(int x,int y,int c)
{
    len++;
    a[len].x=x;
    a[len].y=y;
    a[len].c=c;
    a[len].next=first[x];
    first[x]=len;
}*/

inline int dfs(int x,int sum,int t)
{
    //printf("%d %d %d |\n",x,sum,t);
    if(sum>ans)return 0;
    if(t==n)
    {
        /*for(int i=1;i<=n;++i)
        {
            printf("%d ",road[i]);
        }printf("|%d | %d | %d\n",road[t-1],s[road[t-1]],sum);*/
        if(sum+s[road[t-1]]<ans)ans=sum+s[road[t-1]];
        return 0;
    }
    for(register int i=d[x].x+1;i<=d[x].y;++i)
    {
        register int y=a[i].y;
        //if(x!=y)
        //{
            //printf("1111");
            if(a[i].c+sum>=ans)return 0; 
            if(sum+(n-t)+1>=ans)return 0;
            //printf("3333");
            if(b[y]==0&&sum+a[i].c+z-minn[y]<ans&&a[i].c)
            {
                //printf("2222");
                b[y]=1;road[t]=y;
                z-=minn[y];
                dfs(y,sum+a[i].c,t+1);
                z+=minn[y];
                b[y]=0;road[t]=0;
            //}
        }   
    }
}

int main()
{
    read(n);
    for(register int i=1;i<=n;++i)
    {
        d[i].x=lenn+1;
        for(register int j=1;j<=n;++j)
        {

            //scanf("%d",&d[j].c);
            len++;
            a[len].x=i;
            a[len].y=j;        
            read(a[len].c); 
            //d[j].y=j;
            ans+=a[len].c;
            if(j==1)
            {
                s[i]=a[len].c;
            }
            if(minn[i]>a[len].c&&i!=j)minn[i]=a[len].c; 
        }
        d[i].y=len;
        z+=minn[i];
        kp(lenn+1,len);//ok
        /*for(register int j=lenn+1;j<=len;++j)
        {
            printf("%d %d %d\n",a[j].x,a[j].y,a[j].c);
        }
        printf("%d %d\n",d[i].x,d[i].y ); */
        lenn=len;
    }
    b[1]=1;
    dfs(1,0,1);
    print(ans);
} 

第一次大规模卡常。。。以前最多写读优或者点luogu的O2
以后要卡常,可以来看自己这个很乱的代码qwq

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值