ICPC North Central NA Contest 2017 部分题解

ICPC North Central NA Contest 2017 部分题解

 

 大意:用最短路径来抓住所有的稀有精灵,DFS求最短路

 

#include <bits/stdc++.h>
#define mem(a) memset(a,0,sizeof(a))
#define forn(i,n) for(int i=0;i<n;++i)
#define for1(i,n) for(int i=1;i<=n;++i)
#define IO std::ios::sync_with_stdio(false); std::cin.tie(0)
#define ll long long
using namespace std;
const int maxn=22;
int n,m,all_mask;
int x[maxn],y[maxn],dist[maxn][maxn];
string name[maxn];
int dp[maxn][1<<maxn],p[maxn];

int dfs(int k,int mask)
{
    if(dp[k][mask]!=-1) return dp[k][mask];
    if(mask==all_mask) return dist[k][n];
    int &ans=dp[k][mask];
    ans=1e9;
    forn(i,n)
    {
        if((1<<i)& mask) continue;
        ans=min(ans,dist[k][i]+dfs(i,mask|p[i]));
    }
    return ans;
}

int main()
{
    cin>>n;
    forn(i,n)
        cin>>x[i]>>y[i]>>name[i];
    forn(i,n)
    forn(j,n)
    if(name[i]==name[j])
        p[i]|=1<<j;
    x[n]=y[n]=0;
    p[n]=1<<n;
    all_mask=(1<<n)-1;
    for(int i=0;i<=n;++i)
    for(int j=0;j<=n;++j)
        dist[i][j]=abs(x[i]-x[j])+abs(y[i]-y[j]);
    memset(dp,-1,sizeof(dp));
    cout<<dfs(n,0)<<endl;
    return 0;
}

 

 C. Urban Design

解题过程:只要使用二分定理,只要判断两个点在哪些线的一侧,根据线的个数的奇偶来判断是否在相同的一块区域之中

#include <bits/stdc++.h>
#define mem(a) memset(a,0,sizeof(a))
#define forn(i,n) for(int i=0;i<n;++i)
#define for1(i,n) for(int i=1;i<=n;++i)
#define IO std::ios::sync_with_stdio(false); std::cin.tie(0)
#define ll long long
#define PI 3.14159265358979323846
using namespace std;
const int maxn=2e4+50;
int n,m,sx,sy,ans;
struct vec{int x1,x2,y1,y2,ans;}a[maxn],b[maxn];

ll cross(int x1,int y1,int x2,int y2){return 1LL*x1*y2-1LL*x2*y1;}

bool PointAndSide(const vec& line,const vec& pts)
{
    int ox=line.x1,oy=line.y1;
    ll dx=line.x2-line.x1,dy=line.y2-line.y1;
    ll a=cross(pts.x1-ox,pts.y1-oy,dx,dy);
    ll b=cross(pts.x2-ox,pts.y2-oy,dx,dy);
    assert(a!=0&&b!=0);
    return (a<0&&b>0)||(a>0&&b<0);
}


int main()
{
    cin>>n;
    forn(i,n)
        cin>>a[i].x1>>a[i].y1>>a[i].x2>>a[i].y2;
    cin>>m;
    forn(i,m)
        cin>>b[i].x1>>b[i].y1>>b[i].x2>>b[i].y2;
    forn(i,n)
    forn(j,m)
    if(PointAndSide(a[i],b[j]))
        b[j].ans++;
    forn(i,m)
    if(b[i].ans%2)
        cout<<"different"<<endl;
    else
        cout<<"same"<<endl;
    return 0;
}

 

G. Sheba's Amoebas

解题思路:没啥幺蛾子,直接DFS爆搜,直接过,数据量也不大

#include <bits/stdc++.h>
#define mem(a) memset(a,0,sizeof(a))
#define forn(i,n) for(int i=0;i<n;++i)
#define for1(i,n) for(int i=1;i<=n;++i)
#define IO std::ios::sync_with_stdio(false); std::cin.tie(0)
#define ll long long
using namespace std;
const int maxn=1e3+50;
char pic[110][110];
int dir[8][2] = { {1, 0}, {0, 1}, {-1, 0}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1} };
bool vis1[110][110],vis2[110][110];
int n,m,sx,sy,ans;


bool check(int x, int y)
{
    if(x >= 1 && x <= n & y >= 1 && y <= m && pic[x][y] == '#' && !vis1[x][y] & ! vis2[x][y])
        return true;
    return false;
}

void dfs(int x,int y,int cnt)
{
    bool flag=false;
    for(int i=0; i<8; ++i)
    {
        int tx=x+dir[i][0],ty=y+dir[i][1];
        if(check(tx,ty))
        {
            vis1[tx][ty]=vis2[tx][ty]=true;
            dfs(tx,ty,cnt+1);
            vis1[tx][ty]=0;
            flag=true;
        }
    }
    if(!flag&&cnt>1)
    {
        for(int i = 0; i <= 7; i++)
        {
            int tx = x + dir[i][0], ty = y + dir[i][1];
            if(tx == sx && ty == sy)
            {
                ans++;
                return;
            }
        }
    }
}

int main()
{
    while(cin>>n>>m)
    {
        mem(vis1);
        mem(vis2);
        for1(i,n)
        for1(j,m)
        cin>>pic[i][j];
        ans=0;
        for1(i,n)
        for1(j,m)
        {
            if(!vis1[i][j]&&pic[i][j]=='#')
            {
                mem(vis1);
                vis1[i][j]=vis2[i][j]=1;
                sx=i,sy=j;
                dfs(i,j,1);
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

H. Zebras and Ocelots

解题思路:将整个排序反过来,然后看O的位置,O在第i位就会产生 2^i 的步骤,用快速幂加一下就OK

#include <bits/stdc++.h>
#define mem(a) memset(a,0,sizeof(a))
#define forn(i,n) for(int i=0;i<n;++i)
#define for1(i,n) for(int i=1;i<=n;++i)
#define IO std::ios::sync_with_stdio(false); std::cin.tie(0)
#define ll long long
using namespace std;
const int maxn=1e3+50;
int n,m,sx,sy,ans;
char c;

ll quick_pow(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1) res*=a;
        a=a*a;
        b=b>>1;
    }
    return res;
}

int main()
{
    while(cin>>n)
    {
        ll ans=0;
        string str;
        forn(i,n)
        {
            cin>>c;
            str+=c;
        }
        //cout<<str<<endl;
        reverse(str.begin(),str.end());
        for(int i=0;i<str.size();++i)
        {
            if(str[i]=='O')
                ans+=quick_pow(2,i);
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

 I. Racing Around the Alphabet

解题思路:纯模拟题,就是依次走,计算最短路径和就行了

#include <bits/stdc++.h>
#define mem(a) memset(a,0,sizeof(a))
#define forn(i,n) for(int i=0;i<n;++i)
#define for1(i,n) for(int i=1;i<=n;++i)
#define IO std::ios::sync_with_stdio(false); std::cin.tie(0)
#define ll long long
#define PI 3.14159265358979323846
using namespace std;
const int maxn=1e3+50;
int n,m,sx,sy,ans;
double perlen,res;
char lists[28]={' ','\'','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
char dim[200];

int searchx(char x)
{
    for(int i=0;i<28;++i)
    {
        if(lists[i]==x)
            return i+1;
    }
}

int main()
{
    perlen=PI*60.0/28.0;
    while(cin>>n)
    {
        getchar();
        while(n--)
        {
            res=0.0;
            string str;
            getline(cin,str);
            res+=str.size();
            for(int i=0;i<str.size()-1;++i)
            {
                int a=searchx(str[i])-searchx(str[i+1]);
                if(a<0)
                    a=min(abs(a),abs(a+28));
                else
                    a=min(a,28-a);
                //cout<<a<<endl;
                res+=perlen*a/15.0;
            }
            printf("%.10f\n",res);
        }
    }
    return 0;
}

 

J. Lost Map

解题思路:最小生成树,模板题,随便套Kruskal和Prim随便用一个就行了

#include <bits/stdc++.h>
using namespace std;
#define MAX_N 2501
struct edge {
    int from,to;
    long long cost;
}E[MAX_N*MAX_N];

int N,M;//N是点的个数,M是边的数量

int father[MAX_N];
void init()
{
    for(int i=1;i<=N;i++)father[i]=i;
}
int findd(int x)
{
    if(x==father[x])return x;
    return father[x]=findd(father[x]);
}
bool same(int x,int y)
{
    return findd(x)==findd(y);
}
void unite(int x,int y)
{
    int u=findd(x),v=findd(y);
    if(u==v)return;
    father[u]=v;
    return;
}
bool cmp(edge a,edge b)
{
    return a.cost<b.cost;
}
void Kruskal()
{
    sort(E+1,E+1+M,cmp);
    for(int i=1;i<=M;i++)
    {
        if(same(E[i].from,E[i].to))continue;
        unite(E[i].from,E[i].to);
        cout<<E[i].from<<" "<<E[i].to<<endl;
    }
    return;
}
int main()
{
    int x;
    while(~scanf("%d",&N))
    {
        M=0;
        init();
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<N;j++)
            {
                scanf("%d",&x);
                if(x!=0)
                {
                    M++;
                    E[M].from=i+1;
                    E[M].to=j+1;
                    E[M].cost=x;
                }
            }
        }
        Kruskal();
    }
    return 0;
}

 

posted @ 2020-02-29 19:18  小松QAQ  阅读(236)  评论(0编辑  收藏  举报