当前位置: 代码网 > it编程>软件设计>算法 > 洛谷 P3959 [NOIP2017 提高组] 宝藏

洛谷 P3959 [NOIP2017 提高组] 宝藏

2024年07月31日 算法 我要评论
当选了哪几个点时,将其压缩,放入数组,然后跑。了两个点,因为贪心正确性有点…一道奇奇怪怪的类似生成树的题目。

洛谷 p3959 [noip2017 提高组] 宝藏

题目链接洛谷 p3959 [noip2017 提高组] 宝藏


题目大意

一道奇奇怪怪的类似生成树的题目。

半正解 (过不了 h a c k hack hack

d f s + dfs+ dfs+贪心优化。( w a wa wa 了两个点,因为贪心正确性有点…)

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int bignum=1e17;
const int maxn=1000;
const int maxm=4000;
const int maxf=50100;
int hd[maxm],nxt[maxm],to[maxm],l[maxm],bz[maxn],vis[maxn],dep[maxn],fnn[maxn],id[maxn],s[maxf];
int n,m,cnt,top,ans=bignum,maxn;

inline int mymin(int a,int b)
{
	return a<b?a:b;
}
void add(int u,int v,int vl)
{
	nxt[++cnt]=hd[u];
	hd[u]=cnt;
	to[cnt]=v;
	l[cnt]=vl;
	nxt[++cnt]=hd[v];
	hd[v]=cnt;
	to[cnt]=u;
	l[cnt]=vl;
}
void qsort(int l,int r)
{
	int i=l,j=r,mid=fnn[((l+r)>>1)+1];
	while(i<=j)
	{
		while(fnn[i]>mid)i++;
		while(fnn[j]<mid)j--;
		if(i<=j)
		{
			int op=fnn[i];
			fnn[i]=fnn[j];
			fnn[j]=op;
			op=id[i];
			id[i]=id[j];
			id[j]=op;
			i++,j--;
		}
	}
	if(l<j)qsort(l,j);
	if(i<r)qsort(i,r);
}

void dfs(int p,int sum,int fnn)
{
//	cout<<p<<endl;
	if(sum>ans) return ;
	if(p==n)
	{
		ans=mymin(ans,sum);
		return ;
	}
	for(int i=1;i<=top;i++)
	{
		if(sum>ans) return ;
		for(int j=hd[vis[i]];j;j=nxt[j])
		{
//			if(sum>ans) return ;
			if(sum+(dep[vis[i]]+1)*l[j]>ans) continue ;
		//	printf("%lld %lld\n",fnn[to[j]],ss*l[j]);
			if(bz[to[j]]==0&&s[fnn+(1<<to[j])]>sum+(dep[vis[i]]+1)*l[j])
			{
				bz[to[j]]=1;
				vis[++top]=to[j];
				dep[to[j]]=dep[vis[i]]+1;
				s[fnn+(1<<to[j])]=sum+dep[to[j]]*l[j];
			//	fnn[to[j]][dep[vis[i]+1]]=(dep[vis[i]]+1)*l[j];
				dfs(p+1,sum+dep[to[j]]*l[j],fnn+(1<<to[j]));
				vis[top]=0;
				top--;
				dep[to[j]]=0;
				bz[to[j]]=0;
			}
	//		else maxn=min(maxn,s[fnn+(1<<to[j])]);
		}
	}
}

signed main()
{
//	freopen("treasure.in","r",stdin);
//	freopen("treasure.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++) id[i]=i;
	for(int i=1;i<=m;i++)
	{
		int u,v,vl;
		scanf("%lld%lld%lld",&u,&v,&vl);
		if(u!=v)
		{
			add(u,v,vl);
		}
	}
	qsort(1,n);
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=50000;j++) s[j]=bignum;
		top=0;
	//	s[(1<<id[i])]=0;
		vis[++top]=id[i];
		bz[id[i]]=1;
		dfs(1,0,(1<<id[i]));
		bz[id[i]]=0;
		
	}
//	cout<<maxn<<endl;
	printf("%lld",ans);
	return 0;
}

正解

神犇都用 d p dp dp ,我用 d f s + dfs+ dfs+状压优化。
当选了哪几个点时,将其压缩,放入数组,然后跑 d f s dfs dfs

#include<bits/stdc++.h>
#define int long long
using namespace std;

const int inf=1e16;
const int maxn=1100;
int vis[maxn],l[maxn],d[maxn];
int c[maxn][maxn],to[maxn][maxn];
int ans=inf,tmp,tot,cnt,n,m,sum;

void qsort(int l,int r,int p)
{
	int i=l,j=r,mid=c[p][to[p][(l+r)/2+1]];
	while(i<=j)
	{
		while(c[p][to[p][i]]<mid)i++;
		while(c[p][to[p][j]]>mid)j--;
		if(i<=j)
		{
			swap(to[p][i],to[p][j]);
		//	swap(c[p][to[p][i]],c[p][to[p][j]]);
			i++,j--;
		}
	}
	if(l<j)qsort(l,j,p);
	if(i<r)qsort(i,r,p);
}

void dfs(int num,int node)
{
    for(int i=num;i<=sum;i++) 
	{
        if(tot+cnt*l[vis[i]]>=ans) return;
        for(int j=node;j<=d[vis[i]];j++)
        if(!l[to[vis[i]][j]])
		{ 
            sum++; 
            vis[sum]=to[vis[i]][j]; 
            cnt-=c[vis[sum]][to[vis[sum]][1]]; 
            tot+=c[vis[i]][vis[sum]]*l[vis[i]]; 
            l[vis[sum]]=l[vis[i]]+1; 
            dfs(i,j+1);
            tot-=c[vis[i]][vis[sum]]*l[vis[i]];
            l[vis[sum]]=0;
            cnt+=c[vis[sum]][to[vis[sum]][1]];
            sum--;
        }
        node=1;
    }
    if(sum==n)
	{
        if(tot<ans) ans=tot;
        return;
    }
}

signed main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
    {
    	for(int j=1;j<=n;j++)
    	{
    		c[i][j]=inf;
		}
	}
    for(int i=1;i<=m;i++)
	{
		int u,v,vl;
        scanf("%lld%lld%lld",&u,&v,&vl);
        if(c[u][v]<vl) continue ;
        if(c[u][v]==inf) to[u][++d[u]]=v,to[v][++d[v]]=u;
        c[u][v]=c[v][u]=vl;
    }
    for(int i=1;i<=n;i++)
	{
		qsort(1,d[i],i);
        cnt+=c[i][to[i][1]];
    }
    for(int i=1;i<=n;i++)
	{
        tot=0,sum=1;
        vis[1]=i;
        cnt-=c[i][to[i][1]];
        l[i]=1;
        dfs(1, 1);
        l[i]=0;
        cnt+=c[i][to[i][1]];
    }
    printf("%lld",ans);
    return 0;
}

简单易懂!!!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com