您的位置:首页 > 其它

poj 几道简单的搜索题(三)

2016-07-15 00:12 344 查看
题目:poj 2531

题意:

给出n(n<=20)个点,及点与点之间的权值,把这n个点划分成两个集合,使这两个集合中点与点之间的边权和最 大?

分析:

n=20,暴力枚举的时间复杂度才O(2^20*C),C是求和的时间常数。2000ms的时间足够了。暴力枚举的话可以子集枚举和递归(时间接近1000ms)。

这题递归的话可以剪枝,可以优化到32ms,方法是参考:http://blog.csdn.net/martin31hao/article/details/8098302

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=22;
int n,ans;
int w

;
bool in
;
void dfs(int k,int sum)
{
in[k]=1;  //0表示在0集合,1表示在1集合
int t=sum;
for(int i=0;i<n;i++)
if(in[i])t-=w[k][i];
else t+=w[k][i];
if(t>ans)ans=t;
for(int i=k+1;i<n;i++)  //看下一个点
if(t>sum){    //剪枝,只有t>sum才考虑以后的选择情况
dfs(i,t); //把i放到1集合
in[i]=0; //不放
}
}
int main()
{
memset(in,0,sizeof(in));
scanf("%d",&n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)scanf("%d",&w[i][j]);
ans=0;
dfs(0,0);
printf("%d\n",ans);
return 0;
}
题目:poj 1416

题意:

整数划分问题,要求把所给整数划分,使得划分得到的的数的和尽量接近一个目标数字。

分析:

枚举划分的个数,dfs分配划分的位置,然后把划分的数加起来求和即可。

我是用一个string保存划分位置,最后再按照string保存的划分位置再求和。

剪枝的话应该是每划分一次就把所得到的和,与未划分的数加起来,然后与已经得到最优解比较,判断是否剪枝即可。

我的代码没优化,懒得改了QAQ。

#include<cstdio>
#include<iostream>
#include<stack>
#include<vector>
#include<cstring>
using namespace std;
int n,ans,total,ansnum,len;
vector<int>vec;
string as;
void dfs(int tot,int id,int k,string s)
{
if(tot==0){
int i=0,sum=0;
int pre=0;
for(;i<=id;i++){
int x=s[i]-'0';
int j=x-1,w=1,num=0;
while(j>=pre){
num+=vec[j--]*w;
w*=10;
}
pre=x;
sum+=num;
}
if(sum>ans&&sum<=total)ans=sum,ansnum=1,as=s,len=id;
else if(sum==ans)ansnum++;
return;
}
for(int i=k+1;i<vec.size();i++){  //枚举划分的位置
string t=s;
t[id]=(char)(i+'0');
dfs(tot-1,id+1,i,t);
}
}
void change(int x)
{
stack<int>s;
while(x){
s.push(x%10);
x/=10;
}
while(!s.empty())vec.push_back(s.top()),s.pop();
}
int main()
{
while(~scanf("%d%d",&total,&n)&&(total+n)){
vec.clear();
ans=-1;
change(n);
string s="1234567";
for(int i=0;i<vec.size();i++){ //枚举划分的个数
s[i]=(char)('0'+vec.size());
dfs(i,0,0,s);
}
if(ans==-1)printf("error\n");
else if(ansnum>1)printf("rejected\n");
else{
printf("%d",ans);
int i=0,sum=0;
int pre=0;
for(;i<=len;i++){
int x=as[i]-'0';
int j=x-1,w=1,num=0;
while(j>=pre){
num+=vec[j--]*w;
w*=10;
}
pre=x;
printf(" %d",num);
}
printf("\n");
}
}
return 0;
}


题目:poj 2676

题意:

完成数独9*9,使每一行,每一列,每一小块3*3,都是由1-9组成

分析:

把没放数的位置先找出来,然后dfs一个个放数。用三个数组标记一下以放数的行,列和块。

看Discuss说反搜更快。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=11;
typedef pair<int,int>pii;
pii q[N*N];
bool cow

,row

,blo

; //列,行,块
int a

;
int id[9][9]={0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2,0,0,0,1,1,1,2,2,2, //每个位置所属的块
3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,3,3,3,4,4,4,5,5,5,
6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8,6,6,6,7,7,7,8,8,8};
bool flag;
int cnt;
bool dfs(int s)
{
if(flag)return 1;
if(s==cnt){
flag=1;return 1;
}
bool ok=1;
int r=q[s].first,c=q[s].second;
for(int k=1;k<=9;k++){
if(!row[r][k]&&!cow[c][k]&&!blo[id[r][c]][k]){
a[r][c]=k; row[r][k]=cow[c][k]=blo[id[r][c]][k]=1;
if(dfs(s+1))return 1;
row[r][k]=cow[c][k]=blo[id[r][c]][k]=0;//a[r][c]=0;
}
}
return 0;
}
int main()
{
int T;scanf("%d",&T);
char s[11];
while(T--){
memset(row,0,sizeof(row));
memset(cow,0,sizeof(cow));
memset(blo,0,sizeof(blo));
flag=0;
cnt=0;
for(int i=0;i<9;i++){
scanf("%s",s);
for(int j=0;j<9;j++){
a[i][j]=s[j]-'0';
int k=a[i][j];
if(k!=0)row[i][k] =cow[j][k] =blo[id[i][j]][k]=true;
else q[cnt++]=make_pair(i,j);
}
}
dfs(0);
for(int i=0;i<9;i++){
for(int j=0;j<9;j++)printf("%d",a[i][j]);
printf("\n");
}

}
return 0;
}


题目:poj 1129

题意:

图的染色问题,相邻点不能染同一种颜色,问需要最少颜色数?

分析:

dfs,依次枚举每个点,给他分配一种可以染的颜色,然后这种颜色从与它相邻的点的可染色中删除,然后再枚举下一个点,继续同样操作。

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N=30;
vector<int>g
; //存边
int n;
bool vis

;
void dfs(int u)
{
if(u==n)return;
int i;
for(i=0;i<n;i++){
if(!vis[u][i]){vis[u][i]=1;break;} //找一种可染色
}
for(int j=0;j<g[u].size();j++){
vis[g[u][j]][i]=1;  //邻接点这种颜色不能用了
}
dfs(u+1);
}
char s
;
int main()
{
while(~scanf("%d",&n)&&n){
for(int i=0;i<n;i++){
scanf("%s",s);
int len=strlen(s);
g[s[0]-'A'].clear();
if(len<=2)continue;
for(int j=2;j<len;j++)
g[s[0]-'A'].push_back(s[j]-'A');
}
memset(vis,0,sizeof(vis));
dfs(0);
int ans=-1;
for(int i=0;i<n;i++){
int j;
for(j=0;j<n;j++)if(!vis[i][j])break;
if(j>ans)ans=j;
}
if(ans==1)printf("1 channel needed.\n");
else printf("%d channels needed.\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: