挑战程序设计竞赛1

1.抽签
你的朋友提议玩一个游戏:将写有数字的 n 个纸片放入口袋中,你可以从口袋中抽取 4 次纸
片,每次记下纸片上的数字后都将其放回口袋中.如果这 4 个数字的和是 m,就是你赢,否
则就是你的朋友赢.请你编写一个程序,判断当纸片上所写的数字是 k1, 
k2,...., kn时,是否存在抽取 4 次和为 m 的方案。如果存在,输出 Yes;否则,输出 No.
 1 ≤ m ≤ 10^8
1 ≤ ki ≤ 10^8
输入
n=3
m=10
k={1,3,5}
输出
No
 

 

1 ≤ n ≤ 50 (n^4)
for (i=1; i<=n; i++)
    for (j=1; j<=n; j++)
        for (k=1; k<=n; k++)
            for (l=1; l<=n; l++)
                if (a[i]+a[j]+a[k]+a[l]==m){
                    f=1;
                    break;
                }
if (f==1)
    printf("Yes\n");
else
    printf("No\n");


    

1 ≤ n ≤ 50 (n^4)
for (i=1; i<=n; i++)
    for (j=1; j<=n; j++)
        for (k=1; k<=n; k++)
            for (l=1; l<=n; l++)
                if (a[i]+a[j]+a[k]+a[l]==m){
                    f=1;
                    break;
                }
if (f==1)
    printf("Yes\n");
else
    printf("No\n");


    

sort(a+1,a+n+1);
for (i=1; i<=n; i++)
    for (j=1; j<=n; j++)
        for (k=1; k<=n; k++){
            l=a[i]+a[j]+a[k];
            if (binary_search(a+1,a+n+1,l)){
                f=1;
                break;
            }
        }
        
1 ≤ n ≤ 1000  (n^2logn)
for (i=1;i<=n;i++)
   for (j=1;j<=n;j++)
   b[i*n+j]=a[i]+a[j];
sort(b+1,b+1+n*n);
for (i=1;i<=n;i++)
   for (j=1;j<=n;j++){
            l=a[i]+a[j];
            if (binary_search(b+1,b+n*n+1,l)){
                f=1;
                break;
            }
        }


    
2.
有n根棍子,棍子i的长度为ai.想要从中选出 3 根棍子组成周长尽可能长的三角形。请输
出最大的周长,若无法组成三角形则输出 0.
3 ≤n ≤100 
1 ≤ai ≤10^6
输入 
n=5
a={2,3,4,5,10}
输出
12

for (i=1; i<=n; i++)
    for (j=i+1; j<=n; j++)
        for (k=j+1; k<=n; k++)
        {
            l=a[i]+a[j]+a[k];
            max1=max(a[i],max(a[j],a[k]));
            k=l-max1;
            if (k>max1)
                ans=max(ans,l);
        }
    printf("%\n",ans); 

3.
poj1852
Ants
n只蚂蚁以每秒1cm的速度在长为L cm的竿子上爬行.当蚂蚁爬到竿子的端点时就会掉落.
由于竿子太细,两只蚂蚁相遇时,它们不能交错通过,只能各自反向爬回去。对于每只蚂蚁,
我们知道它距离竿子左端的距离 xi,但不知道它当前的朝向,请计算所有蚂蚁落下竿子所需
的最短时间和最长时间.
1 ≤ L ≤ 10^6
1 ≤ n ≤ 10^6
0 ≤ xi ≤ L
输入 
L=10
n=3
x={2,6,7}
输出
min=4
max=8
 


首先对于最短时间,看起来所有蚂蚁都朝向较近的端点走会比较好。
事实上,这种情况下不会发生两只蚂蚁相遇的情况,
        而且也不可能在比此更短的时间内走到竿子的端点。
接下来,为了思考最长时间的情况,让我们看看蚂蚁相遇时会发生什么
事实上,可以知道两只蚂蚁相遇后,当它们保持原样交错而过继续前进也不会有任何问题。
这样看来,可以认为每只蚂蚁都是独立运动的,所以要求最长时间,
只要求蚂蚁到竿子端点的最大距离就好了。
这样,不论最长时间还是最短时间,都只要对每只蚂蚁检查一次就好了,
这是O(n)时间的算法。对于限制条件n ≤ 10^6,这个算法是够用的,于是问题得解。

for (i=1; i<=n; i++)
    minT=max(minT,min(a[i],L-a[i]));
for (i=1; i<=n; i++)
    maxT=max(maxT,max(a[i],L-a[i]));
4.
n!=n*(n-1)*(n-2)....*1
int fact(int x){
    if (x==0) return 1;
    return x*fact(x-1);
}

 

5.
fib[i]=fib[i-1]+fib[i-2]
int fib(int x){
    if (x==1) return 1;
    if (x==2) return 2;
    if (f[x]) return f[x];
    return fib[x-1]+fib[x-2];
}

 

6.部分和问题
给定整数 a1,a2....an,判断是否可以从中选出若干数,使它们的和恰好为 k
输入
 n 
1 ≤ n ≤ 20 
-10^8 ≤ ai ≤ 10^8
-10^8 ≤ k ≤ 10^8
输入
n=4
a={1,2,4,7}
k=13
输出
Yes 
bool dfs(int i,int sum){
    if (i==n) return sum==k;
    if (dfs(i+1,sum)) return 1;
    if (dfs(i+1,sum+a[i])) return 1;
    return 0;
} 
if (dfs(0, 0)) printf("Yes\n"); 
 else printf("No\n"); 


 
7.
poj2386
Lake Counting
有一个大小为 N*M 的园子,雨后积起了水.八连通的积水被认为是连接在一起的。请求出
园子里总共有多少水洼?(八连通指的是下图中相对 W 的*的部分)
*** 
*W* 
***  
N, M ≤100 

输入
N=10, M=12 
园子如下图('W'表示积水,'.'表示没有积水)
W........WW. 
.WWW.....WWW 
....WW...WW. 
.........WW. 
.........W.. 
..W......W.. 
.W.W.....WW. 
W.W.W.....W. 
.W.W......W. 
..W.......W.
输出
3

void dfs(int x,int y)
{
    c[i][j]='.';
    for (int i=-1; i<=1; i++)
        for (int j=-1; j<=1; j++)
        {
            int xx=x+i,yy=y+j;
            if (xx>=1&&xx<=n&&yy>=1&&yy<=m&&c[xx][yy]=='W')
                dfs(xx,yy);
        }
}
for (i=1; i<=n; i++)
    for (j=1; j<=m; j++)
        if (c[i][j]=='W')
        {
            ans++;
            dfs(i,j);
        }

8.
迷宫的最短路径
给定一个大小为 N×M 的迷宫。迷宫由通道和墙壁组成,每一步可以向邻接的上下左右
四格的通道移动。请求出从起点到终点所需的最小步数。请注意,本题假定从起点一定
可以移动到终点。
N,M<=100
输入 
N=10, M=10(迷宫如下图所示。'#','.','S','G'分别表示墙壁、通道、起点和终点)
#S######.# 
......#..# 
.#.##.##.# 
.#........ 
##.##.#### 
....#....# 
.#######.# 
....#..... 
.####.###. 
....#...G#
输出
22

 

const int INF=10000000000;
typedef pair<int,int> P;
d[4][2]= {1,0,0,1,-1,0,0,-1}
         int bfs()
{
    queue<P>q;
    for (i=1; i<=n; i++)
        for (j=1; j<=m; j++)
            d[i][j]=INF;
    q.push(P(sx,sy));
    while (q.size())
    {
        P p=q.front();
        q.pop();
        if (p.first==gx&&p.second)
            break;
    }
    for (int i=0; i<4; i++)
    {
        int nx=p.first+d[i][0],ny=p.secon+d[i][1];
        if (nx>=1&&nx<=n&&ny>=1&&ny<=m&&c[nx][ny]=='#'d[nx][ny]==INF)
        {
            q.push(P(nx,ny));
            d[nx][ny]=d[p.first][p.second]+1;
        }
    }
    return d[gx][gy];
}
printf("%d\n",bfs());

9.
特殊状态的枚举
虽然生成可行解空间多数采用深度优先搜索,但在状态空间比较特殊时其实可以很简短
地实现.比如,C++的标准库中提供了next_permutation这一函数,可以把n个元素共n!种不同的排列生
成出来.又或者,通过使用位运算,可以枚举从n个元素中取出k个的共C(n,k)种状态或是某个集合
中的全部子集等。

next_permutation(a,a+n)这一函数,可以把n个元素共n!种不同的排列生成出来

// 生成{0,1,2,3,4,...,n-1}的n!种排列
void permutation(int x,int n)
{
    if (x== n)
    {


        return ;
    }
    for (int i = 0; i < n; i++)
    {
        if (!used[i])
        {
            perm[x] = i;
            used[i] =1;
            permutation(pos + 1, n);
            used[i] =0;
        }
    }

}
  
// 即使有重复的元素也会生成所有的排列
// next_permutation是按照字典序来生成下一个排列的
for (i=1; i<=n; i++)
    a[i]=i;
do
{

}
while (next_permutation(a+1,a+1+n));
// 所有的排列都生成后,next_permutation会返回false

for (i=5; i>=1; i--)
{
    int t=min(A/v[i],c[i]);//v[i] 面值 c[i] 个数
    A=A-t*c[i];
    ans+=t;
}

 

 

pair<int,int>a[1000010];
for (i=1;i<n;i++){
	a[i].first=t[i];
	a[i].second=s[i];
}
sort(a+1,a+n+1);
for (i=1;i<=n;i++)
  if (a[i].second>k){
  	ans++;
  	k=a[i].first;
  }

 

a=0;
b=len-1;
while (a<=b)
{
    l=0;
    for (i=0; a+i<=b; i++)
        if (c[a+i]<c[b-i])
        {
            l=1;
            break;
        }
        else
        {
            l=0;
            break;
        }
    if (l)
        putchar(c[a++]);
    else
        putchar(c[b--]);
}

sort(a+1,a+n+1);
i=1;
while (i<=n)
{
    s=a[i];
    i++;
    while (i<=n&&a[i]<=s+r)
        i++;
    p=a[i-1];
    while (i<=n&&a[i]<=p+r)
        i++;
    ans++;
}

 

priority_queue<int>q;
scanf("%d",&n);
for (i=1; i<=n; i++)
{
    scanf("%d",&a);
    q.push(a);
}
while(q.size())
{
    int k1=q.top();
    q.pop();
    k1=q.top()+k1;
    q.pop();
    ans+=k1;
    q.push(k1);
}

 

int rec(int i,int j,int sum)
{
    if (i==n)
        return sum;
    if (j<w[i])
        return rec(i+1,j,sum);
    else
        return max(rec(i+1,j,sum),rec(i+1,j-w[i],sum+v[i]));
}
记忆化搜索
int rec(int i,int j)
{
    int res;
    if (dp[i][j]>=0)
        return dp[i][j];
    if (i==n)
        return 0;
    if (j<w[i])
        res=rec(i+1,j);
    else
        res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
    return dp[i][j]=res;
}
memset(dp,-1,sizeof(dp));
rec(0,w);

for (i=1; i<=n; i++)
    for (j=m; j>=0; j--)
        if (j<w[i])
            dp[i][j]=dp[i-1][j];
        else
            dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
    for (i=1; i<=n; i++)
        for (j=m; j>=w[i]; j--)
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

 

for (i=0; i<n; i++)
    for (j=0; j<m; j++)
        if (a[i]==b[i])
            dp[i+1][j+1]=dp[i][j]+1;
        else
            dp[i+1][j+1]=max(dp[i-1][j],dp[i][j-1]);
ans=dp[n][m]

 

for (i=1;i<=n;i++)
  for (j=w[i];j<=m;j++)
    dp[j]=max(dp[j],dp[j-w[i]]+v[i]);

 

memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for (i=1; i<=n; i++)
    for (j=maxn*maxv; j>=v[i]; j--)
        dp[i][j]=min(dp[i][j],dp[i][j-v[i]]+w[i]);
for (i=0; i<=maxn*maxv; i++)
    if (dp[i]<=m)
        ans=i;

 

memset(dp,-1,sizeof(dp));
dp[0]=0;
for (i=1; i<=n; i++)
    for (j=0; j<=k; j++)
        if (dp[j]>=0)
            dp[j]=m[i];
        else if (j<a[i]||dp[j-a[i]]<=0)
            dp[j]=-1;
        else
            dp[j]=dp[j-a[i]]-1;
if (dp[k]>=0)
    printf("Yes\n");
else
    printf("No\n");

for (i=1; i<=n; i++)
    dp[i]=1;
for (i=2; i<=n; i++)
    for (j=1; j<i; j++)
        if (a[i]>a[j])
            dp[i]=max(dp[i],dp[j]+1);


 

b[0]=a[0];
l=1;
for (i=1; i<n; i++)
    if (a[i]>b[l])
        b[l++]=a[i];
    else
    {
        k=lower_bound(b,b+l,a[i])-b;
        b[k]=a[i];
    }
ans=l+1;

 

dp[0][0]=1;
for (i=1; i<=m; i++)
    for (j=0; j<=n; j++)
        if (j-i>=0)
            dp[i][j]=(dp[i-1][j]+dp[i][j-i])%M;
        else
            dp[i][j]=dp[i-1][j];

 

 

for (i=0; i<=n; i++)
    dp[i][0]=1;
for (i=0; i<n; i++)
    for (j=1; j<=m; j++)
        if (j-1-a[i]>=0)
            dp[i+1][j]=(dp[i+1][j-1]+dp[i][j]-dp[i][j-1-a[i]]+M)%M;
        else
            dp[i+1][j]=(dp[i-1][j]+dp[i][j]+M)%M;
ans=dp[n][m];

priority_queue<int>q;
tank=p;
A[n+1]=L;
B[n+1]=0;
for (i=1; i<=n+1; i++)
{
    int d=a[i]-pos;
    while (tank<d)
    {
        if (q.empty)
        {
            printf("-1\n");
            return 0;
        }
        tank+=q.top();
        q.pop();
        ans++;
    }
    tank-=d;
    pos=a[i];
    q.push(b[i]);
}

for (i=1; i<=k; i++)
{
    scanf("%d%d%d",&z,&x,&y);
    int x_eat=n+x,x_emeny=n*2+x,y_eat=n+y,y_emeny=n*2+y;
    if ((z==2&&x==y)||x>n||y>n)
    {
        ans++;
        continue;
    }
    if (z==1)
    {
        if (find(x)==find(y_eat)||find(x_eat)==find(y))
            ans++;
        else
        {
            f[find(x_eat)]=find(y_eat);
            f[find(x)]=find(y);
            f[find(x_emeny)]=find(y_emeny);
        }
    }
    else
    {
        if (find(x)==find(y)||find(x_emeny)==find(y))
            ans++;
        else
        {
            f[find(x_eat)]=find(y);
            f[find(y_emeny)]=find(x);
            f[find(x_emeny)]=find(y_eat);
        }
    }
}

 

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值