例题:Uva1601/埃及分数问题/Uva11212 待续
Uva1601/11212 基本都参考了网上的代码,感觉自己的思想还不够,代码写的还不够…
Uva1601 //这题基本是看的网上大佬的代码
大意是几个点从初始位置到结束位置,求最短的时间。最多三个点,2*2的格子里必有障碍物。
主要考建图!
看了书,对于把空格提出来建图十分不理解,以为标记一下就可以了,是我太天真….这一题可以用双向bfs写,待续吧。
感觉主要思想就是把空格提出来,将每个空格看作一个结点,找出空格附近有几个空格可用,记录编号。
再然后就是一个开心的bfs
感觉什么时候都要想一想怎么建图….
#include <bits/stdc++.h>
using namespace std;
#define maxn 300
int way[5][2] = {0,0,0,1,0,-1,1,0,-1,0};
int ukg[maxn]; //每个空格周围有多少个可以走的空格
int kg[maxn][5];//记录当前id的空格周围的可走空格
int st[3],sp[3];
int id[maxn][maxn];
int m,n,k;
bool vis[maxn][maxn][maxn];
int ok(int a,int b,int a1,int b1) //不能互换位置和走到一个格子里
{
if(a1 == b1) return 0;
if(a1 == b && b1 == a) return 0;
return 1;
}
int check(int a,int b,int c)
{
if(a == sp[0] && b == sp[1] && c == sp[2] )return 1;
else return 0;
}
struct node
{
int a,b,c;
int d;
node(int x,int y,int z,int q = 0)
{
a = x; b = y; c = z;
d = q;
}
node(){}
};
int bfs()
{
memset(vis,0,sizeof(vis));
queue<node> Q;
Q.push(node(st[0],st[1],st[2]));
vis[st[0]][st[1]][st[2]] = 1;
while(!Q.empty())
{
node t = Q.front(); Q.pop();
/*cout<<"d "<<t.d<<endl;
cout<<t.a<<' '<<t.b<<' '<<t.c<<endl;
cout<<endl;*/
if(check(t.a,t.b,t.c))
{
printf("%d\n",t.d);
break;
}
for(int i = 0; i < ukg[t.a]; i++)
{
int a1 = kg[t.a][i];
for(int j = 0; j < ukg[t.b]; j++)
{
int b1 = kg[t.b][j];
if(!ok(t.a,t.b,a1,b1)) continue;
for(int k = 0; k < ukg[t.c]; k++)
{
int c1 = kg[t.c][k];
if(!ok(t.a,t.c,a1,c1)) continue;
if(!ok(t.b,t.c,b1,c1)) continue;
if(!vis[a1][b1][c1])
{
vis[a1][b1][c1] = 1;
Q.push(node(a1,b1,c1,t.d+1));
}
}
}
}
}
}
int main()
{
while(~scanf("%d%d%d",&m,&n,&k) && m+n+k)
{
getchar();
memset(id,-1,sizeof(id));
char s[20];
int cnt = 0;
int x[maxn] = {0},y[maxn] = {0};
for(int i = 0; i < n ; i++)
{
cin.getline(s,20);
for(int j = 0; j < m; j++)
{
if(s[j] != '#')
{
x[cnt] = i,y[cnt] = j,id[i][j] = cnt;
if(isupper(s[j])) sp[s[j]- 'A'] = cnt;
else if(islower(s[j])) st[s[j] - 'a'] = cnt;
cnt++;
}
}
}
for(int i = 0; i < cnt; i++)//找出每个空格周围可以走的
{
ukg[i] = 0;
for(int j = 0; j < 5 ; j++)
{
int nx = x[i] + way[j][0],ny = y[i] + way[j][1];
if(id[nx][ny] != -1)
{
kg[i][ukg[i]++] = id[nx][ny];
}
}
}
if(k <= 2)//不满3个补齐 说起来我一直觉得是分情况。。按我的想法写代码会非常难看
{
ukg[cnt] = 1; kg[cnt][0] = cnt;sp[2] = cnt;st[2] = cnt++;
}
if(k <= 1)
{
ukg[cnt] = 1; kg[cnt][0] = cnt;sp[1] = cnt; st[1] = cnt++;
}
// cout<<sp[0]<<' '<<sp[1]<<' '<<sp[2]<<endl;
bfs();
}
return 0;
}
埃及分数问题
给你两个数 b a 求b/a = 1/c1 + 1/c2 + 1/c3 …… 要求c1 c2 c3…… 不能重复,而且cn数量越小越好,最小的分数越大越好。
按照紫书的代码敲了一遍。
思想: 迭代加深搜索
即每次给定一个上界 maxd,每次只在这个层数内搜索是否有解。因为这种题目没有明显的上限,直接dfs会超时,而且找到答案也找了很多不必要的分支。
再往下 就是IDA*算法,讲道理才接触我觉得这一题我还想勉强想到限定上界,但是求这个乐观估价函数。。。自我感觉IDA*就是花式剪枝。
//埃及分数问题
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define maxn 15
int ans[maxn];
int v[maxn];
int a,b;
int maxd = 1;
int gcd(int n, int m)
{
return m ? gcd(m,n%m): n ;
}
int get_first(int aa,int bb)
{
int c = 1;
for(; c <= bb; c++)
{
int g = gcd(c,bb);
int x = c/g*bb;
if(x/c <= aa*x/bb)
break;
}
return c;
}
int better(int d)
{
for(int i = d; i >= 0; i-- )
{
if(v[i] != ans[i])
{
return ans[i] == -1 || v[i] < ans[i];
}
return false;
}
}
int dfs(int d,int from,int aa,int bb)
{
//cout<<from<<endl;
if(d == maxd)
{
if(bb % aa) return 0;
v[d] = bb/aa;
if(better(d)) memcpy(ans,v,sizeof(v));
return 1;
}
bool ok = 0;
from = max(from,get_first(aa,bb));
for(int i = from; ;i++)
{
if(bb*(maxd+1-d) <= i*aa)break;
v[d] = i;
int b2 = bb*i;
int a2 = aa*i - bb;
int g = gcd(a2,b2);
if(dfs(d+1,i+1,a2/g,b2/g)) ok = true;
}
return ok;
}
int main()
{
while(~scanf("%d%d",&a,&b))
{
int ok = 0;
maxd = 1;
for(; ; maxd ++)
{
memset(ans,-1,sizeof(ans));
if(dfs(0, get_first(a,b),a,b))
ok = 1;
if(ok) break;
}
for(int i = 0; i <= maxd; i++)
printf("%d ",ans[i]);
printf("\n");
}
return 0;
}
uva11212
给出n个自然段,用复制粘贴的方法将其变成有序。
主要思想按紫书。
感觉这类题目最难的位置也就是思考如何剪枝,求乐观估价函数….限制层数。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define sint sizeof(int)
#define N 10
int data[N],moni[N],last[N];
int t,dep = 1;
int ok()
{
for(int i = 0; i < t ; i++)
if(moni[i] != i+1) return 0;
return 1;
}
int hs() //判断后续不正确的数字个数
{
int sum = 0;
for(int i = 1; i < t ; i++)
if(moni[i] != moni[i-1]+1) sum++;
return sum;
}
int cu(int i,int j, int k)
{
int l[N],x = 0,num = j-i+1;
memcpy(l,last,sizeof(last));
memcpy(moni+k,last+i,sint*num);
for(int a = i ; a+num < t ; a++)
l[a] = l[a+num];
for(int a = 0; a < k;a++)
moni[a] = l[x++];
for(int a = k+num; a < t; a++)
moni[a] = l[x++];
return 1;
}
int dfs(int n)
{
if(n == dep)
return ok();
else
{
if( hs() + n*3 > dep*3) return false;
int old[N];
memcpy(old,moni,sizeof(moni));
memcpy(last,old,sizeof(last));
for(int i = 0; i < t ; i++)
for(int j = i; j < t; j++)
for(int k = 0; k < t-(j-i); k++)
{
if(i == k) continue;
cu(i,j,k);
if(dfs(n+1) == 1) return true;
memcpy(moni,old,sizeof(old));
memcpy(last,old,sizeof(old));
}
return false;
}
}
int main()
{
int num = 1;
// freopen("D://in.txt","r",stdin);
while(~scanf("%d",&t) && t)
{
for(int i = 0; i < t ; i++)
scanf("%d",&data[i]);
dep = 0;
memcpy(moni,data,sizeof(data));
int ok = 0;
int cnt = hs();
ok = cnt == 0;
if(!ok)
{
for(; dep <= t-1; dep++)
if(dfs(0) == 1) break;
}
printf("Case %d: %d\n",num++,ok ? 0 : dep);
}
return 0;
}