https://vjudge.net/contest/148064
Password: acmlab2016
A - Oil Deposits
【题意】
找出图中‘@’相邻构成的连通块。水平,垂直或对角线相邻都算相邻。
【思路】
DFS.
【Code】
#include<cstdio>
int n,m,ans;
char a[101][101];
int d[101][101];
int dx[8]={0,1,1,1,0,-1,-1,-1};
int dy[8]={1,0,-1,1,-1,-1,1,0};
void dfs(int x,int y)
{
for (int i=0;i<8;i++)
{
int xx=x+dx[i],yy=y+dy[i];
if (xx<0||xx>=n||yy<0||yy>=m||a[xx][yy]=='*') continue;
a[xx][yy]='*';
dfs(xx,yy);
}
}
int main()
{
while(scanf("%d %d",&n,&m)&&n)
{
for (int i=0;i<n;i++)
scanf("%s",a[i]);
ans=0;
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
if (a[i][j]=='@')
{
a[i][j]='*';
ans++;
dfs(i,j);
}
printf("%d\n",ans);
}
return 0;
}
B - Meteor Shower
【题意】
有M个流星要砸下来,流星i在时刻Ti (0 ≤ Ti ≤ 1,000) 砸到(Xi, Yi) (0 ≤ Xi ≤ 300; 0 ≤ Yi ≤ 300),以及与它相邻的四连块,有个人从(0, 0)出发,每时刻移动1个单位距离,问最少花费多少时间可以移动到安全位置(永远没有流星砸到的地方)
【思路】
预处理一下图,然后BFS。
【Code】
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int n;
int d[306][306];
bool v[306][306];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
struct node{
int x,y,step;
};
queue<node> q;
int bfs()
{
memset(v,0,sizeof(v));
q.push((node){0,0,0});
v[0][0]=true;
while(!q.empty())
{
node p=q.front();
for (int i=0;i<4;i++)
{
int x=p.x+dx[i],y=p.y+dy[i],step=p.step+1;
if (x<0||y<0||v[x][y]||d[x][y]<=step) continue;
if (d[x][y]==5200000) return step;
v[x][y]=true;
q.push((node){x,y,step});
}
q.pop();
}
return -1;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<306;i++)
for (int j=0;j<306;j++)
d[i][j]=5200000;
for (int i=0;i<n;i++)
{
int x,y,tm;
scanf("%d %d %d",&x,&y,&tm);
d[x][y]=min(tm,d[x][y]);
for (int j=0;j<4;j++)
{
int xx=x+dx[j],yy=y+dy[j];
if (xx>=0&&yy>=0) d[xx][yy]=min(tm,d[xx][yy]);
}
}
int ans=bfs();
printf("%d\n",ans);
return 0;
}
C - Red and Black
【题意】
输入W * H的字符矩阵,求从@出发四个方向运动能到达.的数量,#不可达
【思路】
DFS.
【Code】
#include<cstdio>
int n,m,ans;
char a[25][25];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
void dfs(int x,int y)
{
a[x][y]='#';
ans++;
for (int i=0;i<4;i++)
{
int cx=x+dx[i],cy=y+dy[i];
if (cx<0||cy<0||cx>=n||cy>=m||a[cx][cy]=='#') continue;
dfs(cx,cy);
}
}
int main()
{
while (scanf("%d %d",&m,&n)&&m)
{
for (int i=0;i<n;i++)
scanf("%s",a[i]);
ans=0;
for (int i=0;i<n;i++)
for(int j=0;j<m;j++)
if (a[i][j]=='@') dfs(i,j);
printf("%d\n",ans);
}
}
D - Smallest Difference
【题意】
给你2至10个0~9之间的整数,每个数最多出现一次,组合拆成两个数,求这两个数差值的绝对值的最小值
【思路】
贪心+枚举.
差值最小肯定两个数的位数相等(偶数)或差1位(奇数).然后去枚举这个数列的全排列,找到最小差值.
用到了STL的next_permutation
next_permutation(a,a+n)即a数列前n个数的下一个排列.
类似的还有prev_permutation.
最后一个排列没有下一个排列,用next_permutation会返回false,但是使用了这个方法后,序列会变成字典序列的第一个,如cba变成abc。prev_permutation同理
【Code】
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
getchar();
while (T--)
{
int a[12];
char s[25];
fgets(s,25,stdin);
int len=strlen(s),n=0;
for (int i=0;i<len;i++)
if (s[i]>='0'&&s[i]<='9')
a[n++]=s[i]-'0';
int ans=0x7FFFFFFF;
do {
if ((n>2)&&(a[0]==0||a[n/2]==0)) continue;
int x=0,y=0;
for (int i=0;i<n/2;i++) x=x*10+a[i];
for (int i=n/2;i<n;i++) y=y*10+a[i];
ans = min(ans,abs(x-y));
} while (next_permutation(a,a+n));
printf("%d\n", ans);
}
}
E - Charm Bracelet
【题意】
大小为M的背包最多能装价值为多少的物品
【思路】
P01.
【Code】
#include<cstdio>
#include<algorithm>
int n,m,w[3500],v[3500],f[13500];
int main()
{
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d %d",&w[i],&v[i]);
f[0]=0;
for (int i=1;i<=n;i++)
for(int j=m;j>=w[i];j--)
{
f[j]=std::max(f[j],f[j-w[i]]+v[i]);
//printf("f[%d,%d]=%d\n",i,j,f[j]);
}
printf("%d\n",f[m]);
}
F - Piggy-Bank
【题意】
给定一个储钱罐的容量M,给定N种硬币的价值和重量,问是否能填满储钱罐,能填满则输出储钱罐内钱的最小值
【思路】
P02.
【Code】
#include<cstdio>
#include<algorithm>
int w[505],v[505],f[10050];
const int INF=0x3FFFFFFF;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m,e,t;
scanf("%d %d",&e,&t);
m=t-e;
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d %d",&v[i],&w[i]);
for (int i=0;i<=m;i++) f[i]=INF;
f[0]=0;
for (int i=1;i<=n;i++)
for(int j=w[i];j<=m;j++)
{
f[j]=std::min(f[j],f[j-w[i]]+v[i]);
//printf("f[%d,%d]=%d\n",i,j,f[j]);
}
if (f[m]!=INF) printf("The minimum amount of money in the piggy-bank is %d.\n",f[m]);
else printf("This is impossible.\n");
}
}