ICPC North Central NA Contest 2017部分題解

eg:A題大模擬(感覺),D題dp,F題沒看。這三題沒有出,其餘七道題的題解,這次還是按照難度順序來吧。
比賽傳送門

G. Sheba’s Amoebas

題意:判斷連通圓環的個數。
題解:bfs dfs亂搞即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int n,m,ans,stx,sty;
int vis[110][110],tmp[110][110];
int dis[10][2]={1,0,-1,0,0,1,0,-1,1,1,1,-1,-1,1,-1,-1};
char s[110][110];
void dfs(int x,int y,int tot){
	int flag=0;
	for(int i=0;i<8;i++){
		int nx=x+dis[i][0],ny=y+dis[i][1];
		if(nx<0 || nx>=n || ny<0 || ny>=m || s[nx][ny]!='#' || vis[nx][ny] || tmp[nx][ny])continue;
		vis[nx][ny]=1;
		tmp[nx][ny]=1;
		dfs(nx,ny,tot+1);
		vis[nx][ny]=0;
		flag=1;
	}
	if(!flag && tot>1){
		for(int i=0;i<8;i++){
			int nx=x+dis[i][0],ny=y+dis[i][1];
			if(nx==stx && ny==sty){
				ans++;
				return;
			}
		}
	}
}
int main(){
	scanf("%d%d",&n,&m); 
	for(int i=0;i<n;i++)scanf("%s",&s[i]);
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++){
			memset(vis,0,sizeof(vis));
			if(!vis[i][j] && s[i][j]=='#'){
				vis[i][j]=1;
				tmp[i][j]=1;
				stx=i,sty=j;
				dfs(i,j,1);
			}
		}
	printf("%d\n",ans);
	return 0;
}

H. Zebras and Ocelots

題意:一排動物Z和O,每次將最底下的O變成Z,同是該O底下的Z全變成O,問一直到全爲Z需要操作幾次。
題解:模擬一下會發現,就是二進制加法,Z爲1O爲0,那(1<<(n+1)-1-給出的數字即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
char a[100],ch;
int n;
ll sum,ans,f[100];
int main(){
	f[0]=1;
	for(int i=1;i<=60;i++)f[i]=f[i-1]*2;
	scanf("%d%c",&n,&ch);
	for(int i=n-1;i>=0;i--)scanf("%c%c",&a[i],&ch);
	for(int i=0;i<n;i++)ans=ans+f[i];
	for(int i=0;i<n;i++)
		if(a[i]=='Z')sum=sum+f[i];
	printf("%lld\n",ans-sum);
	return 0;
}

I. Racing Around the Alphabet

題意:一個半徑給定的圓盤上面有不同的字abcdefghijklmnopqrtsuvwxyz空格和單引號,先給出一句話,問怎麼使人在圓盤上移動能寫出整句話來。
題解:正着跑反正跑比較一下,取個小累加即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int T;
char s[maxn],ch;
map<char,int>a;
int main(){
	for(char i='A';i<='Z';i++)a[i]=i-'A'+1;
	 a[' '] = 27;a['\'']=28;
    double dis = 3.1415926535 * 60 / 28;
	scanf("%d%c",&T,&ch);
	while(T--){
		cin.getline(s,200);
		int len=strlen(s),pos=s[0],cnt=0;
		for(int i=1;i<len;i++){
			int cmp=abs(a[s[i]]-a[s[i-1]]);
			cnt+=min(cmp,28-cmp);
		}
		double ans=(double)cnt*dis/(double)15.0+(double )len;
		printf("%.10lf\n",ans);
	}
	return 0;
}

C. Urban Design

題意:一個平面被若干條直線劃分,每個區域都需要被劃分爲商業區或者居民區,先給出兩個點,問是否在同一個區。
題解:判斷兩點經過多少條直線,如果經過偶數條直線說明可以劃分爲同一個區,反之不可以。用叉乘判斷是否相交。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const double eps=1e-6;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
struct arr{
	double s1,s2,e1,e2;
}a[maxn];
int n,q;
double cross(arr a,double x,double y){
	return (a.s1-x)*(a.e2-y)-(a.e1-x)*(a.s2-y); 
} 
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%lf%lf%lf%lf",&a[i].s1,&a[i].s2,&a[i].e1,&a[i].e2);
	scanf("%d",&q);
	while(q--){
		double s1,s2,e1,e2;
		int sum=0;
		scanf("%lf%lf%lf%lf",&s1,&s2,&e1,&e2);
		for(int i=1;i<=n;i++)
			if(cross(a[i],s1,s2)*cross(a[i],e1,e2)>eps)continue;
			else sum++;
		if(sum%2)puts("different");
		else puts("same");
	} 
	return 0;
}

J. Lost Map

題意:給出最短路的圖,反推原圖。
題解:最小生成樹,依次加邊即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N=3e3+10;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}int n,cnt;
int a[N][N]; int f[N];

struct node{
    int u,v,w;
} E[N*N],ans[N];

int getf(int x){
    return x==f[x] ? x : f[x] = getf(f[x]);
}

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

int main() {

    scanf("%d",&n);

    for(int i=1;i<=n;i++) f[i] = i;

    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&a[i][j]);
            if(j<i) {
                ++cnt; 
                E[cnt].u = i, E[cnt].v = j, E[cnt].w = a[i][j];
            }
        }	
    }

    sort(E+1,E+cnt+1,cmp);

    int mk = 0;
    for(int i=1;i<=cnt;i++){
        node t = E[i];
        int u = t.u, v = t.v; swap(u,v);
        if(getf(u)!=getf(v)){
            f[getf(u)] = getf(v); //cout<<u<<' '<<v<<' '<<getf(u)<<' '<<getf(v)<<" h"<<endl;
            ++mk;
            ans[mk].u = u, ans[mk].v = v;
        }
    }

    for(int i=1;i<=mk;i++){
        printf("%d %d\n",ans[i].u,ans[i].v);
    }
	return 0;
}

E. Is-A? Has-A? Who Knowz-A?

題意:定義兩種關係 is 和 has,A is B代表A可以是B 但是 B不可以是 A,A has B代表 B是A的兒子。
給出若干條關係定義 再給出若干條詢問 判斷正誤。
題解:可以bfs亂搞 也可以傳遞閉包。注意到is是可以無限傳遞下去的,而has的關係與is的關係有關。所以先處理完is關係矩陣,再處理has關係矩陣。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
string a,b,c;
map<string,int>mmap;
int n,m,T;
int is[510][510],has[510][510];
int main(){
//	freopen("1.txt","w",stdout);
	scanf("%d%d",&m,&T);
	for(int i=1;i<=m;i++){
		cin>>a>>b>>c;
		if(!mmap.count(a))mmap[a]=++n;
		if(!mmap.count(c))mmap[c]=++n;
		if(b[0]=='i')is[mmap[a]][mmap[c]]=1;
		else has[mmap[a]][mmap[c]]=1;
	}
	for(int i=1;i<=n;i++)is[i][i]=1;
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				is[i][j]=is[i][j]||(is[i][k] && is[k][j]);
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++){
				has[i][j]=has[i][j]||(has[i][k] && has[k][j]);
				has[i][j]=has[i][j]||(is[i][k] && has[k][j]);
				has[i][j]=has[i][j]||(has[i][k] && is[k][j]);
			}
	for(int ttt=1;ttt<=T;ttt++){
		cin>>a>>b>>c;
		printf("Query %d: ",ttt);
		if(!mmap.count(a))mmap[a]=++n;
		if(!mmap.count(c))mmap[c]=++n;
		if(b[0]=='i'){
			if(is[mmap[a]][mmap[c]])puts("true");
			else puts("false");
		}else{
			if(has[mmap[a]][mmap[c]])puts("true");
			else puts("false");
		}
	}
	return 0;
}

B. Pokemon Go Go

題意:二維平面tsp問題,每種寶可夢只需抓一隻,問最少花費。
題解:狀壓dp,用1表示該點是否需要走到,0就是不走。然後類似於floyd的轉移即可。最後用dfs判斷每種只取一個的花費,選擇一個最小的。f[i][j]f[i][j]表示 i 這種二進制情況到 j 這個點的最小花費。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
ll read(){
    ll f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
int n,m,ans;
struct arr{
	int x,y;
}a[22];
int d[22][22],f[1<<22][22];
map<string,int>mmap;
string s;
vector<int>v[22];
void dfs(int cnt,int x){
	if(cnt==m){
		ans=min(ans,f[x][0]);
		return;
	}
	for(int i=0;i<v[cnt+1].size();i++)
		dfs(cnt+1,(x|(1<<v[cnt+1][i])));
	return;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d%d",&a[i].x,&a[i].y);
		cin>>s;
		if(mmap.count(s))v[mmap[s]].push_back(i);
		else {
			mmap[s]=++m;
			v[mmap[s]].push_back(i);
		}
	} 
	a[0].x=0,a[0].y=0;
	for(int i=0;i<=n;i++)
		for(int j=0;j<=n;j++)
			d[i][j]=abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y);
	memset(f,INF,sizeof(f));
	f[0][0]=0;
	for(int i=0;i<(1<<(n+1));i++)
		for(int j=0;j<=n;j++)
			for(int k=0;k<=n;k++)
				if((i & (1<<j))==0)
					f[i|(1<<j)][j]=min(f[i|(1<<j)][j],f[i][k]+d[k][j]);
	ans=INF;
	dfs(0,1);
	printf("%d\n",ans);			
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章