ICPC North Central NA Contest 2017 (部分)

链接:https://www.jisuanke.com/contest/7331?view=challenges
B Pokemon Go Go
题意:在100x100的方格纸上有n只精灵(n<=20),它们都有自己的名字或者是种类,你需要抓到所有种类的精灵(每种只能一个,种类数不超过15),问你从00点出发再回到00点你经过的最小距离是多少。
种类数m<=15,n<=20,不大的数据范围非常适合状压dp 复杂度刚好是0(n ^ 2 * 2 ^ m)
既然每种种类只能有一个那状态就表示种类,那就需要处理一下每个精灵的种类了,编个1开始的号,那么第二个下标表示啥呢,种类肯定不行了(你只知道从那个种类过来的但是是那个点呢,一个种类可以有许多点的)那就用点呗,太菜了没想通这一点。。。最后在满状态里取最小值就可以了。需要注意点的坐标可能为负。

#include<iostream>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=21;
int n,x[N],y[N],cnt,sz[N];
map<string,int> mp;
int dp[1<<N][N];
int dis(int i,int j)
{
	return abs(x[i]-x[j])+abs(y[j]-y[i]);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		string s;
		cin>>x[i]>>y[i]>>s;
		if(!mp[s])//处理种类
		{
			mp[s]=++cnt;
			sz[i]=cnt;
		}
		else sz[i]=mp[s];
	}
	memset(dp,0x3f,sizeof dp);
	for(int i=0;i<(1<<cnt);i++)
	{
		for(int j=1;j<=n;j++)
		{
			if((i&(1<<(sz[j]-1)))==0) continue;
			if(i==(1<<(sz[j]-1))) 
			{
				dp[1<<(sz[j]-1)][j]=dis(0,j);
				continue;
			}
			for(int k=1;k<=n;k++)
				if((i&(1<<(sz[k]-1)))&&sz[j]!=sz[k])
					dp[i][k]=min(dp[i][k],dp[i-(1<<(sz[k]-1))][j]+dis(j,k));
		}
	}
	int ans=0x3f3f3f3f;
	for(int i=1;i<=n;i++)
		ans=min(dp[(1<<cnt)-1][i]+dis(0,i),ans);
	cout<<ans;
	return 0;
 } 

G dfs大水题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int d[8][2]={0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,-1,-1,1};
int n,m,cnt;
char s[200][200];
bool st[200][200];
void dfs(int x,int y)
{
	st[x][y]=1;
	for(int i=0;i<8;i++)
	{
		int dx=x+d[i][0],dy=d[i][1]+y;
		if(!st[dx][dy]&&s[dx][dy]=='#')
			dfs(dx,dy);
	}
}
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++)
    		if(!st[i][j]&&s[i][j]=='#')
    		{
    			dfs(i,j);
    			cnt++;
    		}
    printf("%d",cnt);
    return 0;
} 

H (找规律)

没一次变只能变最下面的O,就是说每次到哪一个O时一定是O下面全是Z,变一次之后这个位置下面就全是O 了,所以变低i位就是变前i-1位的和在加1,所以求个前缀和就好了其实最后打表会发现第i位就是 1<<i ;(1<<60应该没爆ll啊,不知道为啥错了,直接高精度就好了)

#include<vector>
#include<iostream>
using namespace std;
typedef unsigned long long ull;
const int N=100010;

int n,m,cnt;
vector<int> sum[100],a[100];
vector<int> add(vector<int> &A, vector<int> &B)
{
    if (A.size() < B.size()) return add(B, A);
    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }
    if (t) C.push_back(t);
    return C;
}

char s[100];
int main(){
    cin>>n;
    for(int i=n;i;i--)
    	cin>>s[i];
    vector<int>  ans,res;
    res.push_back(1);
    for(int i=1;i<=n;i++)
    {
		a[i]=add(sum[i-1],res);
		sum[i]=add(a[i],sum[i-1]);
    	if(s[i]=='O')
    	{
    		ans=add(ans,a[i]);
		}
	}
	for(int i=ans.size()-1;i>=0;i--)
    	printf("%d",ans[i]);
    return 0;
} 

I 每到一步求一下向两边走的步数最小值就可以了,刚开始看错题意了,wa了好久

#include<vector>
#include<iostream>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const int N=100010;
int n;
const double pi=3.14159265358;
char s[100];
map<char,int> mp;
bool check(char c)
{
	if(c==' '||(c>='A'&&c<='Z'))return 0;
	else return 1;
}
int main(){
	for(int i=1;i<=26;i++)
		mp[char(i+'A'-1)]=i;
	mp[' ']=27;
    cin>>n;
    getchar();
    double res=pi*60/28.0;
    while(n--)
	{
		string s;
		vector<int> ve;
		getline(cin,s);
		int cnt=0;
		for(int i=0;i<s.size()-1;i++)
		{
			if(check(s[i])&&check(s[i+1])) continue;
			else if(check(s[i]))
			{
				cnt+=min(28-mp[s[i+1]],mp[s[i+1]]);
			}
			else if(check(s[i+1]))
			{
				cnt+=min(28-mp[s[i]],mp[s[i]]);
			}
			else 
			{
				int x=abs(mp[s[i]]-mp[s[i+1]]); 
				cnt+=min(x,28-x);
			}
		}
		double ans=(res*(cnt))/15.0+s.size();
		printf("%.8lf\n",ans);
	 } 
    return 0;
}

J 最小生成树模板题

#include<vector>
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
typedef  long long ull;
const int N=2510,INF=0x3f3f3f3f;
int n,g[N][N],dist[N];
bool st[N];
vector<pair<int,int> > ve;
map<int,int> mp;
void prim()
{
    memset(dist, 0x3f, sizeof dist);

    for (int i = 0; i < n; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;

        if (i && dist[t] == INF) return ;

        if (i)ve.push_back({mp[t],t});
        st[t] = true;

        for (int j = 1; j <= n; j ++ )
			if(dist[j] > g[t][j])
			{
				dist[j]=g[t][j];
				mp[j]=t;
			}
    }
    return ;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			cin>>g[i][j];
	prim();
	for(int i=0;i<ve.size();i++)
		cout<<ve[i].first<<' '<<ve[i].second<<endl;
    return 0;
} 
发布了26 篇原创文章 · 获赞 3 · 访问量 603

猜你喜欢

转载自blog.csdn.net/qq_45288870/article/details/104594533