每天一套题打卡|河南省第八届ACM/ICPC

A 挑战密室

化学方程式求分子量
这题我懒得写了

可以用map<string,int>哈希表,表示每种分子的相对分子质量
之后,从头遍历到尾。
1.数字:连读直到不是数字
2.字母:连读直到不是字母
3.括号:从左括号开始遍历,重复1、2,到右括号退出

下面这个代码可以AC,但是有bug的,数字超过10,或者字母连着>3个就挂了

#include<cstdio>
#include<cstring>
#include<map>
#include<string>
using namespace std; 
map<string,int> x;
int main()
{
	x["N"]=14;x["C"]=12;x["O"]=16;x["Cl"]=35;x["S"]=32;x["H"]=2;x["Al"]=27;x["Ca"]=40;x["Zn"]=65;x["Na"]=23;
    int t;scanf("%d",&t);
    char ch[52],xx[3];
    while (t--)
    {
    	int i;
    	scanf("%s",ch);int ll=strlen(ch);
    	for (i=0;i<ll;i++)
    	if (ch[i]=='=')
    	break;
    	int lplp=1;
    	i++;int s,ss=0,ks;
    	if ('0'<ch[i]&&ch[i]<='9')
		{
			lplp=ch[i]-'0';
		    i++;
	    }
    	for (;i<ll;i++)
    	{
    		if (ch[i]=='+')
    		break;
    		if (ch[i]=='(')
    		{
    			s=0;i++;
    			for (;;i++)
    			{
    				if (ch[i]==')') break;
    				if ('A'<=ch[i]&&ch[i]<='Z')
    				{
    					xx[0]=ch[i];
    					xx[1]=0;
    					if ('a'<=ch[i+1]&&ch[i+1]<='z')
    					{
    						i++;
    						xx[1]=ch[i];
    						xx[2]=0;
    					}
    				}
    				ks=x[xx];
    				if ('0'<ch[i+1]&&ch[i+1]<='9')
    		    	{
    		    		i++;
    			    	ks*=ch[i]-'0';
    			    }
    			    s+=ks;
    			}
    			if ('0'<ch[i+1]&&ch[i+1]<='9')
    			{
    				i++;
    				s*=ch[i]-'0';
    			}
    			ss+=s;
    		}
    		else
    		{
    			if ('A'<=ch[i]&&ch[i]<='Z')
				{
					xx[0]=ch[i];
					xx[1]=0;
					if ('a'<=ch[i+1]&&ch[i+1]<='z')
					{
						i++;
						xx[1]=ch[i];
						xx[2]=0;
					}
				}
				ks=x[xx];
				if ('0'<ch[i+1]&&ch[i+1]<='9')
		    	{
		    		i++;
			    	ks*=ch[i]-'0';
			    }
			    ss+=ks;
    		}
    	}
    	ss*=lplp;
    	printf("%04d\n",ss);
    }
	return 0;
}

B 最大岛屿

dfs统计连通分量模板

void dfs(int x,int y){
	flood[x][y] = area;
	for(int i=0;i<8;i++){
		int tx = x + dr[i][0];
		int ty = y + dr[i][1];
		if(in(tx,ty) && a[tx][ty] == 1 && flood[tx][ty] == 0){
			dfs(tx,ty);
		}
	}
}

主要注意地图的读写,中间有空格,可以用getchar读取

#include<bits/stdc++.h>
using namespace std;

const int maxn = 510;
int m,n,t;
int a[maxn][maxn];
int area = 0;
int flood[maxn][maxn];
int dr[8][2] = {{0,1},{0,-1},{-1,0},{1,0},{1,-1},{-1,1},{-1,-1},{1,1}};
int s[maxn*maxn];

bool in(int x,int y){
	return x>=1 && x<=n && y>=1 && y<=m;
}

void dfs(int x,int y){
	flood[x][y] = area;
	for(int i=0;i<8;i++){
		int tx = x + dr[i][0];
		int ty = y + dr[i][1];
		if(in(tx,ty) && a[tx][ty] == 1 && flood[tx][ty] == 0){
			dfs(tx,ty);
		}
	}
}

int main(){
	cin>>n>>m>>t;
	getchar();
	char ch;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			while((ch = getchar()) == ' '){}
			a[i][j] = ch - '0';
		}
		getchar();
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(flood[i][j] == 0 && a[i][j] == 1){
				area++;
				dfs(i,j);
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(flood[i][j] != 0){
				s[flood[i][j]]++;
			}
		}
	}
	long long maxarea = 0;
	for(int i=1;i<=area;i++){
		if(s[i] > maxarea) maxarea = s[i];
	}
	cout<<area<<" "<<maxarea*t<<endl;
	return 0;
} 

C 最少换乘

写bfs搜索(求最短路)过的
首先把所有与起点1同一路线的点都入队(step表示换成次数 = 0)
bfs每次取出头部,搜索
当两点时同一公交路线时,新状态step不变
当两点不是同一公交路线时,新状态step+1

vis二维数组标记这条边是否走过

另外注意:这道题读入比较麻烦
没有告诉我们 每行有多少个数

我用getline函数来读的,getline(std::cin,string),读入到字符串string中

其他博客写的题解,用单源点最短路dijkstra做的 https://blog.csdn.net/dreamlandz/article/details/51509382

#include<bits/stdc++.h>
using namespace std;


const int maxn = 510;
int g[maxn][maxn];
int t;
int n,m;
int a[maxn];
int vis[maxn][maxn];
struct edge{
	int u;
	int w;
	edge(int uu = 0,int ww = 0){
		u = uu;
		w = ww;
	}
};
vector<edge> v[maxn];
int sstation;
int estation;
struct node{
	int xx;
	int station;
	int step;
	node(int xxx,int stations,int steps){
		xx = xxx;
		station = stations;
		step = steps;
	}
};

int bfs(){
	queue<node> q;
//	q.push(node(1,3,0)); //这里应该把和a相连的全部入队 就是下面几行 
	for(int i=0;i<v[1].size();i++){
		vis[1][v[1][i].u]= 1;
		q.push(node(v[1][i].u,v[1][i].w,0));
	}
	int ans = 0x3f3f3f3f;
	while(!q.empty()){
		int x = q.front().xx;
		int sta = q.front().station;
		int step = q.front().step;
		if(x==n){
			ans = min(ans,step);
		}
		q.pop();
		for(int i=0;i<v[x].size();i++){
			if(vis[x][v[x][i].u]) continue;
			if(v[x][i].w == sta){
				vis[x][v[x][i].u] = 1;
				q.push(node(v[x][i].u,sta,step));
			}else{
				vis[x][v[x][i].u] = 1;
				q.push(node(v[x][i].u,v[x][i].w,step+1));
			}
		}
	}
	return ans;
}


int main(){
	cin>>t;
	while(t--){
		memset(vis,0,sizeof(vis));
		cin>>m>>n;
		getchar();
		for(int i=1;i<=m;i++){
			string temp;
			getline(std::cin, temp);
			int len = 0;
			for(int j=0;j<temp.length();j++){
				int sum = 0;
				while(j < temp.length() && temp[j] != ' '){
					sum = sum*10 + (temp[j] - '0');
					j++;
				}
				a[len++] = sum;
			}
			for(int j=0;j<len;j++){
				for(int p = j+1;p<len;p++){
					v[a[j]].push_back(edge(a[p],i));
				}
			}
		}
		int ans = 0;
		ans = bfs();
		if(ans == 0x3f3f3f3f){
			cout<<"NO"<<endl;
		}else{
			cout<<ans<<endl;
		}
		for(int i=0;i<maxn-1;i++){
			v[i].clear();
		} 
	}
	return 0;
} 

D 引水工程

最小生成树,prim和kru...都可以过

kru最小生成树
建图时 自己对自己也算一条边(如果要选条边,不能算n-1条边里)

#include<bits/stdc++.h>
using namespace std;

/*
想法1: 
	kru最小生成树
	建图时 自己对自己也算一条边(如果要选条边,不能算n-1条边里)
*/

/*
想法2:从权值最小的开始建水库 prim算法 
*/


//kru做法
int n,m,minn,father[305],sum,tem[305];
struct node
{
    int x,y,l;
}a[90005];

bool cmp(node a,node b)
{
    return a.l<b.l;
}

int find(int x)                      //  做了时间上的优化 ,但是 在空间复杂度上比较高
{
    if(x!=father[x])
        father[x]=find(father[x]);
    sum++;
    return father[x];
}

bool merge(int x,int y)    // 做了时间复杂度上的优化  让并查集的 深度尽量  浅
{
    int sum1,sum2;
    sum=0;
    x=find(x);
    sum1=sum;        //    x  的深度
    sum=0;
    y=find(y);
    sum2=sum;       //    y   的深度
    if(x!=y)
    {
        if(sum1>sum2)
            father[y]=x;
        else
            father[x]=y;
        return true;
    }
    else
        return false;
}
int main()              //  先用  Dijkstra 做一次   // Dijkstra 是 根据边来做的
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0;i<=n;i++)
            father[i]=i;
        int q=0;
        //i从0开始 多输了一次 
        for(int i=0;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                int e;
                scanf("%d",&e);
                a[q].x=j;
                a[q].y=i;
                a[q].l=e;
                q++;
            }
        }
        int sum3=0,count1=0;
        sort(a,a+q,cmp);
        for(int i=0;i<q;i++)
        {
            if(merge(a[i].x,a[i].y))
            {
                sum3+=a[i].l;
                count1++;
            }
            if(count1==n) // 如果边数等于 所有需要连接的 点数-1的话 就跳出去
                break;
        }
        printf("%d\n",sum3);
    }
    return 0;
}

Prim求最小生成树
在选择最小邻接边时,和顶点再比较一下

#include<bits/stdc++.h>
using namespace std;


const int inf = 0x3f3f3f3f;
const int maxn = 510;
bool vis[maxn];
int dist[maxn];
int g[maxn][maxn];
int a[maxn];
int n,t;

//想法2:从权值最小的开始建水库 prim算法
//有水可以自身引水 或者其它地区引水 所以如果 最小的邻接边的费用 比对应顶点的权值大 就自己引水

int Prim(int pos){
	int ans = 0;
	memset(vis,false,sizeof(vis));
	ans = a[pos];
	vis[pos] = true;
	for(int i=1;i<=n;i++) dist[i] = g[pos][i];
	for(int i=1;i<=n-1;i++){
		int minc = inf;
		int p = -1;
		for(int j=1;j<=n;j++){
			if(!vis[j] && minc > dist[j]){
				minc = dist[j];
				p = j;
			}
		}
		//应题目中的要求(每个点都要有水)
		//有水可以自身引水 或者其它地区引水 所以如果 最小的邻接边的费用 比对应顶点的权值大 就自己引水 
		if(minc > a[p]){
			ans += a[p];
			vis[p] = true;
			continue;
		}
		
		vis[p] = true;
		ans += dist[p];
		for(int j=1;j<=n;j++){
			if(!vis[j] && dist[j] > g[p][j]){
				dist[j] = g[p][j];
			}
		}
	}
	return ans;
}

int main(){
	cin>>t;
	while(t--){
		cin>>n;
		int minv = inf;
		int pos = 1;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			if(a[i] < minv){
				minv = a[i];
				pos = i;
			}
		}

		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				cin>>g[i][j];
			}
		}
		cout<<Prim(pos)<<endl;
	}
	return 0;
}

F Distribution

校赛也出了这一道题,比较简单
给定两条线,求一三象限 与 二四象限 上的 点数差

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1100;
int n,m;
int g[maxn][maxn]; // 0开始(0也算)
int maxx = 0;
int maxy = 0;

int solve(int x,int y){
	int sum = 0;
	for(int i=0;i<x;i++){
		for(int j=0;j<y;j++){
			if(g[i][j] == 1) 
				sum++;
		}
	}
	for(int i=x+1;i<=maxx+1;i++){
		for(int j=y+1;j<=maxy+1;j++){
			if(g[i][j] == 1) 
				sum++;
		}
	}
	return sum;
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		int xi,yi;
		cin>>xi>>yi;
		g[xi][yi] = 1;
		if(xi > maxx) maxx = xi;
		if(yi > maxy) maxy = yi;
	}
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		int ans1 = 0;
		int ans2 = 0;
		ans1 = solve(x,y);
		ans2 = n - ans1;
		cout<<ans1 - ans2<<endl;
	}
	return 0;
} 

G Interference Signal

题意:给定n个数,求最大的 至少连续m个数的平均值
枚举起点,算平均值就可以了

#include<bits/stdc++.h>
using namespace std;

const int maxn = 2050;
int t;
int a[maxn];
int sum[maxn];
int n,m;

int main(){
	cin>>t;
	while(t--){
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			cin>>a[i];
			a[i] = a[i] * 1000;
		}
		memset(sum,0,sizeof(sum));
		sum[0] = 0;
		for(int i=1;i<=n;i++){
			sum[i] = sum[i-1] + a[i];
		}
		double average = 0;
		for(int i=1;i<=n;i++){
			for(int j=i+m-1;j<=n;j++){
				double avetemp = (sum[j] - sum[i-1])*1.0/ (j-i+1);
				if(avetemp > average) average = avetemp;
			}
		}
		int ans = average;
		printf("%d\n",ans);
	}
	return 0;
} 
posted @ 2019-05-01 20:40  fishers  阅读(233)  评论(0编辑  收藏  举报