F题
题目链接:点击打开链接
题意:中文题,自己看!!
题解:这道题最常规的解法是对于每一袋米都可以有两个尝试:选择或者不选择。那就会有2^N种可能。一直选到自己的钱满了。。
然后每次更新最大值。。
这种解法是没错,但是N是可以达到1000*20.。。这绝对是Time Limit Exceeded。不可能Accepted。
所以现在算法的重要性就体现出来了。。
01背包问题。。
dp[i]代表有i的钱数最多可以买多少重量的大米。。。
然后有:dp[i] = Max(dp[i],dp[i-V[j]]+W[j]);
详情的背包问题:背包九讲
#include<cstdio>
#include<cstring>
int dp[120];
int W[20003];
int V[20003];
int Max(int a,int b)
{
return a>b?a:b;
}
int main()
{
int t;
scanf("%d",&t);
int n,m;
int p,h,c,b = 0;
int i,j;
while(t--)
{
b = 0;
scanf("%d%d",&n,&m);
for(j=0;j<m;j++)
{
scanf("%d%d%d",&p,&h,&c);
for(i=0;i<c;i++)
{
V[b] = p;
W[b++] = h;
}
}
memset(dp,0,sizeof(dp));
for(j=0;j<b;j++)
for(i=n;i>=0;i--)
{
if(i>=V[j])
{
dp[i] = Max(dp[i],dp[i-V[j]]+W[j]);
}
}
printf("%d\n",dp[n]);
}
return 0;
}
G:
题目链接:点击打开链接
题意:给出一个4*4的棋盘,里面只有b:黑色。w:白色两种。然后问你最少多少次可以将棋盘翻转为全黑或者全白状态。。
没翻转一次它的上下左右都要翻转。。
题解:分析问题发现对于每个棋子最多只能翻转一次。因为两次以上就和翻转0次和1次重复了。完全没有必要。。
所以我们巧用二进制的思想。
对于每一个棋子可以选择翻或者不翻。。
如果二进制为 100000000000001
就代表除了第一个和最后一个翻转其余的都不用翻转。。
然后变成十进制。。
然后每一种状态都是0000000000000000~~1111111111111111
0~2^16;
然后对于每一种状态枚举。。
#include<stdio.h>
#include<string.h>
char map[6][6];
int var[6][6];
int min(int a,int b)
{
return a>b?b:a;
}
int tran(int l)
{
int bit = 0,i,j;
for(i=1;i<5;i++)
for(j=1;j<5;j++)
if(map[i][j]=='b')
var[i][j] = 1;
else
var[i][j] = 0;
int bitnum = 0;
while(l)
{
if(l%2)
{
int x = bit/4+1;
int y = bit%4+1;
var[x][y] = !var[x][y];
var[x-1][y] = !var[x-1][y];
var[x+1][y] = !var[x+1][y];
var[x][y-1] = !var[x][y-1];
var[x][y+1] = !var[x][y+1];
bitnum++;
}
l = l/2;
bit++;
}
return bitnum;
}
int check(int k)
{
int i,j;
int b = 0;
for(i=1;i<5;i++)
for(j=1;j<5;j++)
{
if(var[i][j])
{
b++;
}
}
if(b==0 ||b==16)
return k;
else
return 20;
}
int main()
{
int i,j;
while(scanf("%s",map[1]+1)!=EOF)
{
for(i=2;i<5;i++)
scanf("%s",map[i]+1);
int l = 1<<16;
int ans = 20;
for(i=0;i<l;i++)
{
int k = tran(i);
int num = check(k);
ans = min(ans,num);
}
if(ans==20)
printf("Impossible\n");
else
printf("%d\n",ans);
}
return 0;
}