A: Balloons
题目大意:对于判定两个气球是否相邻,Saya and Kudo 有两种不同的观点,Saya认为对于 A 和 B
满足
时,可以认为两个气球相邻,对于Kudo, 当元素 A
和 B
满足
同时
时,两个气球相邻。问:以两人各自的观点,各有多少个气球连通块。
题目实质,用两次搜索。判断各有多少个连通块。
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 110;
char chr[maxn][maxn];
int vis[maxn][maxn];
int n;
int dis[4][2] = {{0,1},{0,-1},{-1,0},{1,0}};
void dfs1(int r,int c,int id) {
if(r<0 || r>=n||c<0||c>=n)
return ;
if(vis[r][c] > 0 || chr[r][c] != '1')
return ;
vis[r][c] = id;
for(int dr = -1;dr<=1;dr++) {
for(int dc = -1;dc<=1;dc++) {
if(dr != 0 || dc!= 0)
dfs1(r+dr,c+dc,id);
}
}
}
void dfs2(int r,int c,int id) {
if(r<0 || r>=n||c<0||c>=n)
return ;
if(vis[r][c] > 0 || chr[r][c] != '1')
return ;
vis[r][c] = id;
for(int dr = -1;dr<=1;dr++) {
for(int dc = -1;dc<=1;dc++) {
if(dr+dc==-1 || dr+dc==1 )
dfs2(r+dr,c+dc,id);
}
}
}
int main() {
int flag = 1;
while(scanf("%d",&n) !=EOF) {
if(n==0)
return 0;
getchar();
for(int i = 0;i<n;i++) {
scanf("%s",chr[i]);
}
memset(vis,0,sizeof(vis));
int cnt=0;
for(int i = 0;i < n;i++) {
for(int j = 0;j < n;j++) {
if(vis[i][j] == 0 && chr[i][j] == '1')
dfs1(i,j,++cnt);
}
}
memset(vis,0,sizeof(vis));
int cnt2 = 0;
for(int i = 0;i < n;i++) {
for(int j = 0;j < n;j++) {
if(vis[i][j] == 0 && chr[i][j] == '1')
dfs2(i,j,++cnt2);
}
}
printf("Case %d: ",flag++);
printf("%d ",cnt2);
printf("%d\n",cnt);
printf("\n");
}
}
C: Shopping
题目大意:一排商店从最左端到最右端,再从最右端到最左端,问路程是多少。
解题思路一:对这一组数进行从小到大的排序,用后方的值减去前方相邻的值,最后用最后方的值减去最前方的值,将它们的和累加。
解题思路二:找到这组数中的最大值与最小值,两者相减再乘2。(这两种方法本质上一样,但方法二更简便,但是容易想不到)
代码一:
#include<iostream>
#include<cstdio>
#include <algorithm>
using namespace std;
int main() {
long long n;
long long arr[100000];
while (scanf("%lld", &n) != EOF) {
if (n == 0)
return 0;
for (int i = 0; i < n; i++) {
scanf("%lld", &arr[i]);
}
sort(arr, arr + n);
long long sum = 0;
int i;
for (i = 1; i < n; i++) {
sum = sum + arr[i] - arr[i - 1];
}
sum += arr[i - 1] - arr[0];
printf("%lld\n", sum);
}
return 0;
}
代码二:
#include<iostream>
#include<cstdio>
#include <algorithm>
#include<cmath>
using namespace std;
int main() {
long long n;
long long arr[100000];
while (scanf("%lld", &n) != EOF) {
if (n == 0)
return 0;
for (int i = 0; i < n; i++) {
scanf("%lld", &arr[i]);
}
sort(arr, arr + n);
long long int sum = abs(arr[n - 1] - arr[0])*2;
printf("%lld\n", sum);
}
return 0;
}
D:Emergency
题目大意:第一行输入三个数N,M,Q 分别代表几个城市,有几条路(起始点,终止点,道路长度),几行操作指令(0或1两种)0表示x城市被夺回 1表示从x到y城市的最短路径,注意,只可以经过被收回的城市。
由三个0结束输入。
对于输出:若指令为1,当起始点或终止点有一个未被收回时,就输出 City XXX or YYY is not available.
当起始点与终止点均被收回,但中间的路不通时,就输出 No such path.
可通就直接输出最短路的长度。
若指令为0,当0后方的城市不是第一次出现时,就输出 City XXX is already recaptured.
代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
#define inf 0x3f3f3f3f
using namespace std;
int maap[500][500];
int vis[500];
int main()
{
int u,v,w;//起始,终止,长度
int N,M,Q;
int cnt=1;
while(scanf("%d%d%d",&N,&M,&Q)&&(N&&M&&Q))
{
printf("Case %d:\n",cnt++);
/* 为标记两道路之间长度的数组赋初值*/
for(int i=0;i<=N;i++)
for(int j=0;j<=N;j++)
{
if(i==j) maap[i][j]=0;//自身到自身长度为0
else maap[i][j]=inf;//到别处先设为无穷大
}
/* 标记道路是否已收回*/
memset(vis,0,sizeof(vis));
/*输入道路*/
for(int i=0;i<M;i++)
{
scanf("%d%d%d",&u,&v,&w);
maap[u][v]=min(w,maap[u][v]);//在这里就优先找到x到y距离的最小值
}
/*接下来为0 1操作*/
int x,y,flag;
for(int i=0;i<Q;i++)
{
scanf("%d",&flag);
if(flag)//1操作
{
scanf("%d%d",&x,&y);
if(vis[x]==0||vis[y]==0)
printf("City %d or %d is not available.\n",x,y);
else
{
if(maap[x][y]==inf) printf("No such path.\n");
else
printf("%d\n",maap[x][y]);
}
}
else//0操作
{
scanf("%d",&x);
if(vis[x])
printf("City %d is already recaptured.\n",x);
else
{
vis[x]=1;
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
maap[i][j]=min(maap[i][x]+maap[x][j],maap[i][j]);
}
}
}
printf("\n");
}
return 0;
}
E: Fairy tale
这题猛一看以为是搜索
题目大意:给n个数,最多可以挑4个数,这四个数可以挑选重复的值,问:在和不超过M的前提下,所能得到的最大值。
解题思路:做题时一直认为是多重背包,但这里数值太大,开不了这么大的数组。
实际上是利用了数之间的组合以及二分。
代码如下:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int cmp(int a,int b)
{
return a<b;
}
int main()
{
int n,m;
int a,b[1010];
int sum[100010];//存任意两个数之间的和
int cas=1;
while(scanf("%d%d",&n,&m)&&n&&m)
{
b[0]=0;//合法的第一个数记为0//它的存在,使每个数自身能在sum数组中存在
int cnt=1;int k=0;
for(int i=0;i<n;i++)
{
scanf("%d",&a);
if(a<m)
b[cnt++]=a; //筛选
}
for(int i=0;i<cnt;i++)//由于b数组第一个0的存在,这里数组sum[]内含有一个数本身,还有任两个数的和(不同数和相同数的)
for(int j=i;j<cnt;j++)
{
if(b[i]+b[j]<=m)
sum[k++]=b[i]+b[j];
}
sort(sum,sum+k,cmp);
/*
上方已完成1个数的单独组合或者是两个数之间的组合,因为这里最多可以找四个数进行累加,
所以可以对sum[]数组再进行一次组合,找到最终的最大值
用二分法进行查找
*/
int maxx=0;
for(int i=0;i<k;i++)
{
int low=i;int high=k-1;//注意这里的low=i
while(low<=high)
{
int mid=(low+high)/2;
if(sum[i]+sum[mid]>m)
high=mid-1;
else
{
maxx=max(maxx,sum[i]+sum[mid]);
low=mid+1;
}
}
}
cout<<"Case "<<cas++<<": "<<maxx<<endl;//冒号后有空格,因为这个wr
cout<<endl;
}
return 0;
}
G: Hello World!
题目大意:
输入n行数据,每一行的两个元素代表某一值的横坐标与纵坐标。在这n行数据中,找到一个横坐标与纵坐标值均大于它的。多种输出方案优先选择行最小的情况,其次选择列最小的,若找不到,则输出-1 -1 ,以0行结束,每个测试案例后均有一个空行。
代码:
#include<iostream>
#include<cstdio>
#include <algorithm>
using namespace std;
const int maxn=1010;
struct node {
int x, y;
};
node a[maxn], arr[maxn];
bool cmp(node a, node b) {
if (a.x == b.x)
return a.y < b.y;
return a.x < b.x;
}
int main() {
int n;
int flag = 1;
while (scanf("%d", &n) != EOF) {
if(n==0)
return 0;
for (int i = 1; i <= n; i++)
scanf("%d%d", &a[i].x, &a[i].y);
for (int i = 1; i <= n; i++) {
arr[i].x = a[i].x;
arr[i].y = a[i].y;
}
printf("Case %d:\n",flag++);
sort(a + 1, a + 1 + n, cmp);
bool t = false;
int i,j;
for (i = 1; i <= n; i++) {
t=false;
for (j = 1; j <= n; j++) {
if (a[j].x > arr[i].x && a[j].y > arr[i].y) {
printf("%d %d\n",a[j].x,a[j].y);
t=true;
break;
}
}
if(j==n+1 && !t) {
printf("-1 -1\n");
}
}
printf("\n");
}
return 0;
}
H: Ivan comes again!
题目大意:G题的升级版
find操作与G题意思相同,这里add操作是增加一个元素,两值代表横纵坐标;remove操作是删除一个元素,两值代表横纵坐标。
set<pair<int,int> >S; 默认比较规则先按照first 排序,再按照second排序!
代码如下:
这里数值太大,相同代码提交有时AC,有时就TLE。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
using namespace std;
struct node
{
int first,second;
}p;
bool operator <(node a,node b)
{
if(a.first == b.first) return a.second < b.second;
return a.first < b.first;
}
int main()
{
//pair<int,int>p;
int n;
int cas=1;
char ch[10];
//set< pair<int,int> >s;
set<node>s;
set<node>::iterator it;
while(cin >> n && n)
{
s.clear();
printf("Case %d:\n", cas++);
for(int i=0;i<n;i++)
{
scanf("%s",ch);
scanf("%d%d",&p.first,&p.second);
if(ch[0]=='a')
s.insert(p);
else if(ch[0]=='r')
s.erase(p);
else
{
for(it = s.lower_bound(p);it!=s.end();it++)
{
if(it->first > p.first && it->second > p.second)
{
printf("%d %d\n",it->first,it->second);
break;
}
}
if(it==s.end())
printf("-1\n");
}
}
printf("\n");
}
return 0;
}
通过这个题,又知道了 set<pair<int,int> >S这个东西.