zoukankan      html  css  js  c++  java
  • 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*的较多

  • 相关阅读:
    Maven关于web.xml中Servlet和Servlet映射的问题
    intellij idea的Maven项目运行报程序包找不到的错误
    修改Maven项目默认JDK版本
    刷题15. 3Sum
    刷题11. Container With Most Water
    刷题10. Regular Expression Matching
    刷题5. Longest Palindromic Substring
    刷题4. Median of Two Sorted Arrays
    刷题3. Longest Substring Without Repeating Characters
    刷题2. Add Two Numbers
  • 原文地址:https://www.cnblogs.com/cjjsb/p/8902145.html
Copyright © 2011-2022 走看看