• POJ2531&&1416&&2676&&1129


    搜索专题的最后一块了,也告别了这些老的东西了

    接下来就是些全新的内容了啊!

    这次的标签是简单搜索技巧和剪枝,也就是优化爆搜

    当然,像Dancing links这样的玄学操作还是没有的

    2531

    题意:给你n个点,你可以把它们分成两组,求所有不同组别之间的点的边权和。

    爆搜O(2^20*10)理论上也不会超时,但POJ的老爷机并不是Luogu,所以我们要剪枝

    假设刚开始所有点默认都在0号集合(共0,1两个集合),那么对于一个点,先将它移到1号集合中,看看得到的边权和与之前相比是否减小。若减小了就剪枝。

    一个小贪心,正确性显然

    注意如果边权和与之前相比变大了仍然要枚举在0号集合的状况

    CODE

    #include<cstdio>
    using namespace std;
    const int N=25;
    int a[N][N],n,ans;
    bool vis[N];
    inline char tc(void)
    {
    	static char fl[100000],*A=fl,*B=fl;
    	return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0; char ch=tc();
    	while (ch<'0'||ch>'9') ch=tc();
    	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    inline void DFS(int now,int tot)
    {
    	if (now>n) { ans=tot>ans?tot:ans; return; }
    	vis[now]=1;
    	int res=tot;
    	for (register int i=1;i<=n;++i)
    	if (vis[i]) res-=a[now][i]; else res+=a[now][i];
    	if (res>tot) DFS(now+1,res);
    	vis[now]=0; DFS(now+1,tot);
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	register int i,j;
    	for (read(n),i=1;i<=n;++i)
    	for (j=1;j<=n;++j)
    	read(a[i][j]);
    	DFS(1,0);
    	printf("%d",ans);
    	return 0;
    }
    

    1416

    有一个碎纸机,你可以扔进去一个数(不超过6位),你可以将它切割成几段,但这几段的和必须小于一个给出的target,输出可能的最接近target的值,无解输出error,多解输出rejected

    DFS切割的部位,可以把数字预处理出来

    剪枝:若当前的这种割法会超过target就不枚举

    CODE

    #include<cstdio>
    #include<cstring>
    using namespace std;
    int m,n,num[10][10],sum[10],ans,kinds,cnt;
    bool cut[10],c[10];
    inline char tc(void)
    {
    	static char fl[100000],*A=fl,*B=fl;
    	return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0; char ch=tc();
    	while (ch<'0'||ch>'9') ch=tc();
    	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    inline void write(int x)
    {
    	if (x/10) write(x/10);
    	putchar(x%10+'0');
    }
    inline void init(int n)
    {
    	if (n/10) init(n/10);
    	num[++cnt][1]=n%10;
    }
    inline void DFS(int now,int tot)
    {
    	if (now>cnt)
    	{
    		if (ans==1e9) { ans=tot,kinds=1,memcpy(c,cut,sizeof(c)); return; }
    		if (tot==ans) ++kinds;
    		if (tot>ans) ans=tot,kinds=1,memcpy(c,cut,sizeof(c));
    		return;
    	}
    	if (tot+sum[cnt]-sum[now-1]>m) return;
    	for (register int i=now+1;i<=cnt+1;++i)
    	{
    		if (tot+num[now][i-now]>m) continue;
    		cut[i]=1; DFS(i,tot+num[now][i-now]); cut[i]=0;
    	}
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	register int i,j;
    	read(m); read(n);
    	while (m||n)
    	{
    		cnt=kinds=0; ans=1e9; 
    		memset(cut,0,sizeof(cut)); cut[1]=1;
    		init(n);
    		for (i=1;i<=cnt;++i)
    		{
    			sum[i]=sum[i-1]+num[i][1];
    			for (j=1;i+j-1<=cnt;++j)
    			num[i][j]=num[i][j-1]*10+num[i+j-1][1];
    		}
    		DFS(1,0);
    		if (ans==1e9) { puts("error"); read(m); read(n); continue; }
    		if (kinds>1) { puts("rejected"); read(m); read(n); continue; }
    		write(ans); 
    		for (i=1;i<=cnt;++i)
    		{
    			if (c[i]) putchar(' ');
    			putchar(num[i][1]+'0');
    		}
    		putchar('
    '); read(m); read(n);
    	}
    	return 0;
    }
    

    2676

    数独游戏,每一行,每一列,每一个宫格内的数字为1——9且均不重复

    现在给你一个未完成的数独,输出一个它的合法解

    这个更简单了,在爆搜的基础上直接剪去那些中途就冲突的情况即可

    CODE

    #include<iostream>
    #include<cstring>
    using namespace std;
    const int N=15;
    const int num[9][9]=
    {
    	{1,1,1,2,2,2,3,3,3},
    	{1,1,1,2,2,2,3,3,3},
    	{1,1,1,2,2,2,3,3,3},
    	{4,4,4,5,5,5,6,6,6},
    	{4,4,4,5,5,5,6,6,6},
    	{4,4,4,5,5,5,6,6,6},
    	{7,7,7,8,8,8,9,9,9},
    	{7,7,7,8,8,8,9,9,9},
    	{7,7,7,8,8,8,9,9,9}
    };
    int a[N][N],n;
    bool h[N][N],l[N][N],g[N][N],flag;
    char ch;
    inline void print(void)
    {
    	for (register int i=1;i<=9;++i)
    	{
    		for (register int j=1;j<=9;++j)
    		cout<<a[i][j];
    		cout<<endl;
    	}
    }
    inline void DFS(int x,int y)
    {
    	if (flag) return;
    	if (x>9) { print(); flag=1; return; }
    	int xx=x,yy=y;
    	if (++yy>9) yy=1,++xx;
    	if (a[x][y]) DFS(xx,yy); else
    	{
    		for (register int i=1;i<=9;++i)
    		{ 
    			if (h[x][i]||l[y][i]||g[num[x-1][y-1]][i]) continue;
    			a[x][y]=i; h[x][i]=l[y][i]=g[num[x-1][y-1]][i]=1;
    			DFS(xx,yy);
    			h[x][i]=l[y][i]=g[num[x-1][y-1]][i]=a[x][y]=0;
    		}
    	}
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	register int i,j;
    	std::ios::sync_with_stdio(false);
    	cin>>n;
    	while (n--)
    	{
    		memset(h,0,sizeof(h));
    		memset(l,0,sizeof(l));
    		memset(g,0,sizeof(g));
    		for (i=1;i<=9;++i)
    		for (j=1;j<=9;++j)
    		{
    			cin>>ch; a[i][j]=ch-'0';
    			h[i][a[i][j]]=l[j][a[i][j]]=g[num[i-1][j-1]][a[i][j]]=1;
    		}
    		flag=0; DFS(1,1);
    	}
    	return 0;
    }
    

    1129

    给你一个无向图,要求相邻的两个点的颜色不能重复,让你求最少用多少种颜色就可以将图染上色

    爆搜即可,如果相邻的点已经有这种颜色就不选这种颜色。

    但注意不管怎么样都要搜一下多加一种颜色的可能性

    大坑点输出时注意channel的单复数

    CODE

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=30;
    struct edge
    {
    	int to,next;
    }e[N*N<<1];
    int head[N],col[N],n,cnt,tot;
    char s,t;
    bool sign;
    inline char tc(void)
    {
    	static char fl[100000],*A=fl,*B=fl;
    	return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0; char ch=tc();
    	while (ch<'0'||ch>'9') ch=tc();
    	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
    }
    inline void add(int x,int y)
    {
    	e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;
    }
    inline void write(int x)
    {
    	if (x/10) write(x/10);
    	putchar(x%10+'0');
    }
    inline void print(void)
    {
    	write(tot);
    	if (tot>1) puts(" channels needed."); else puts(" channel needed.");
    }
    inline void DFS(int now)
    {
    	if (sign) return;
    	if (now>n) { print(); sign=1; return; }
    	for (register int i=1;i<=tot;++i)
    	{
    		bool flag=1;
    		for (register int j=head[now];j!=-1;j=e[j].next)
    		if (col[e[j].to]==i) { flag=0; break; }
    		if (flag) col[now]=i,DFS(now+1);
    	}
    	col[now]=++tot; DFS(now+1);
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	register int i,j;
    	for (;;)
    	{
    		read(n); cnt=sign=tot=0;
    		memset(e,-1,sizeof(e));
    		memset(head,-1,sizeof(head));
    		memset(col,0,sizeof(col));
    		if (!n) break;
    		for (i=1;i<=n;++i)
    		{
    			s=tc(); t=tc(); t=tc();
    			while (t>='A'&&t<='Z') add(s-'A'+1,t-'A'+1),t=tc();
    		}
    		DFS(1);
    	}
    	return 0;
    }
    

    其实这次的题目普遍都是可行性剪枝,关于最优化剪枝,一般用A*的较多

  • 相关阅读:
    HBase 文件读写过程描述
    Kafka 部署指南-好久没有更新博客了
    《Python高性能编程》——列表、元组、集合、字典特性及创建过程
    Ansible常用功能
    vim内替换文件内容
    线程队列-queue
    Python多进程
    python多线程知识-实用实例
    夜间模式的实现
    本地通知的实现
  • 原文地址:https://www.cnblogs.com/cjjsb/p/8902145.html
Copyright © 2020-2023  润新知