• (SWERC 2019-20)A G K


    好久没写博客没好好打了。记录一下三道中档题。读题能读死。太⛏了。

    A. Environment-Friendly Travel

    题意:给定二维平面起点、终点,和一些中间点。可以通过最贵的方式从起点到中间点,从中间点到终点。中间点之间存在某些单价便宜的交通方式。费用为距离乘单价。

    设置了一个最远距离,点之间距离为欧式距离向上取整。问从起点到终点不超过最远距离的最小费用。不存在输出-1.

    想法:如果没有最远距离的限制,那这道题就是一个dijkstra最短路了。注意到最远距离不超过100,点也就1000个,那就存下到某个点距离为某数的合法状态,不断dijkstra bfs扩展即可。

    我参考的网上的,用bfs求最短路,不太会分析复杂度V·E。的确跑的慢1000ms以上。测了C队的dijkstra跑的飞快100ms。

    看来还是要堆优化。

    #include <bits/stdc++.h>
    #ifndef ONLINE_JUDGE
    #define debug(x) cout << #x << ": " << x << endl
    #else
    #define debug(x)
    #endif
    using namespace std;
    typedef long long ll;
    const int maxn=1e3+7;
    const int maxe=1e6+7;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    
    int dp[maxn][110],B,T,n;
    int c[110];
    struct point
    {
        int x,y;
    }p[maxn];
    
    vector<pair<int,int> >g[maxn];
    
    int dist(int i,int j)
    {
        double dis=sqrt(double((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y)));
        return (int)ceil(dis);
    }
    struct node
    {
        int id,dis,cost,pre;
    };
    struct edge
    {
        int to,nxt,dis,cost;
    }e[maxe<<1];
    int head[maxn],tot=0;
    void addedge(int u,int v,int dis,int cost)
    {
        e[++tot].to=v;
        e[tot].dis=dis;
        e[tot].cost=cost;
        e[tot].nxt=head[u];
        head[u]=tot;
    }
    
    int ans;
    void bfs(int s,int t)
    {
        queue<node>q;
        ans=inf;
        q.push({s,0,0,-1});
        while(!q.empty())
        {
            node cur=q.front();q.pop();
            int u=cur.id;
            for(int i=head[u];i;i=e[i].nxt)
            {
                int v=e[i].to;
                if(v==cur.pre) continue;
                if(cur.dis+e[i].dis>B) continue;
                if(v==t)
                {
                    ans=min(ans,cur.cost+e[i].cost);
                    continue;
                }
                if(dp[v][cur.dis+e[i].dis]>cur.cost+e[i].cost)
                {
                    dp[v][cur.dis+e[i].dis]=cur.cost+e[i].cost;
                    q.push({v,cur.dis+e[i].dis,cur.cost+e[i].cost,u});
                }
            }
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int xs,ys,xd,yd;
        cin>>xs>>ys>>xd>>yd;
        cin>>B>>c[0]>>T;
        for(int i=1;i<=T;++i) cin>>c[i];
        cin>>n;
        for(int i=0,l,id,type;i<n;++i)
        {
            cin>>p[i].x>>p[i].y>>l;
            while(l--)
            {
                cin>>id>>type;
                g[i].push_back({id,type});
            }
        }
        for(int i=0;i<n;++i)
        {
            for(int j=0;j<g[i].size();++j)
            {
                auto u=g[i][j];
                int id=u.first,type=u.second,dis=dist(i,id);
                addedge(i,id,dis,c[type]*dis);
                addedge(id,i,dis,c[type]*dis);
            }
        }
        p[n]={xs,ys};
        p[n+1]={xd,yd};
        for(int i=0;i<n;++i)
        {
            int dis=dist(i,n);
            addedge(i,n,dis,dis*c[0]);
            addedge(n,i,dis,dis*c[0]);
            dis=dist(i,n+1);
            addedge(i,n+1,dis,dis*c[0]);
            addedge(n+1,i,dis,dis*c[0]);
        }
        int dis=dist(n,n+1);
        addedge(n,n+1,dis,dis*c[0]);
        addedge(n+1,n,dis,dis*c[0]);
        memset(dp,0x3f,sizeof(dp));
        bfs(n,n+1);
        if(ans==inf) ans=-1;
        cout<<ans<<endl;
        return 0;
    }
    View Code

    G. Swapping Places

    题意:S个动物名字,L种两两可以交换的关系(并不传递),N个动物的序列。求字典序最小的动物名字序列。

    想法:发现能交换是一种关系,不能交换也是一种关系,就是这些动物之间必然存在先后顺序,利用先后顺序,想到可以拓扑排序。然后O(N*S)建边,但要求字典序最小,需要处理出各个字符对应的字典序排名序号,同时拓扑排序的时候带权。

    O(n*s+nlogn)。

    #include <bits/stdc++.h>
    #ifndef ONLINE_JUDGE
    #define debug(x) cout << #x << ": " << x << endl
    #else
    #define debug(x)
    #endif
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+7;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    
    map<string,int>mp;
    int in[maxn],idx[maxn],last[220],g[220][220],s,l,n;
    vector<int>to[maxn];
    string ans[maxn];
    
    struct node
    {
        int id,val;
        bool operator < (const node &rhs) const
        {
            return val>rhs.val;
        }
    };
    
    void topsort()
    {
        priority_queue<node>pq;
        for(int i=1;i<=n;++i)
            if(!in[i]) pq.push({i,idx[i]});
        while(!pq.empty())
        {
            node cur=pq.top();pq.pop();
            cout<<ans[cur.val]<<' ';
            for(int i=0;i<to[cur.id].size();++i)
            {
                int v=to[cur.id][i];
                in[v]--;
                if(!in[v]) pq.push({v,idx[v]});
            }
        }
        cout<<endl;
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        cin>>s>>l>>n;
        string str;
        for(int i=1;i<=s;++i)
        {
            cin>>str;
            mp[str]++;
            last[i]=-1;
        }
        int k=1;
        for(auto &u:mp)
        {
            u.second=k;
            ans[k]=u.first;
            k++;
        }
        for(int i=1;i<=l;++i)
        {
            cin>>str;
            int u=mp[str];
            cin>>str;
            int v=mp[str];
            g[u][v]=g[v][u]=1;
        }
        for(int i=1;i<=n;++i)
        {
            cin>>str;
            int now=mp[str];
            idx[i]=now;
            for(int j=1;j<=s;++j)
            {
                if(g[j][now]) continue;
                if(last[j]==-1) continue;
                to[last[j]].push_back(i);
                in[i]++;
            }
            last[now]=i;
        }
        topsort();
        return 0;
    }
    View Code

    K. Birdwatching

    题意:挺绕的。就是求有向图到目标点T只有通过邻接边一条路的点。

    想法:显然与T直接相连的点,是在我们的考虑范围中的,但并不是特别好搞,不能直接去掉这些边,再逐个dfs,会互相影响。

    做法是找出直接相连的点,叫做嫌疑点,这些边不去连接。其他的边反向连接。然后对这些嫌疑点逐个dfs,并记录每个点能从反向建图后的几个嫌疑点到达。能从反向建图后的嫌疑点到达,说明这个点正向能到嫌疑点,也就顺势能到目标点。

    能从多个嫌疑点到达,这样的点显然排除,dfs的同时防止环。

    最后答案就是只能从一个嫌疑点到达目标点,即从自己到达目标点的嫌疑点就是答案。

    #include <bits/stdc++.h>
    #ifndef ONLINE_JUDGE
    #define debug(x) cout << #x << ": " << x << endl
    #else
    #define debug(x)
    #endif
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+7;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    
    vector<int>g[maxn],ans;
    set<int>f[maxn],st;
    
    void dfs(int u,int t)
    {
        if(f[u].size()>1||f[u].count(t)) return;
        f[u].insert(t);
        for(auto it:g[u]) dfs(it,t);
    }
    
    int main()
    {
        int n,m,t;
        scanf("%d%d%d",&n,&m,&t);
        for(int i=1; i<=m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if(v==t) st.insert(u);
            else g[v].push_back(u);
        }
        for(auto &it:st)
            dfs(it,it);
        for(auto &it:st)
            if(f[it].size()==1) ans.push_back(it);
        printf("%d
    ",ans.size());
        for(auto &it:ans) printf("%d
    ",it);
        return 0;
    }
    View Code
  • 相关阅读:
    37. 解数独
    皮尔逊相关系数的计算以及数据的描述性统计
    商业微信小程序开发实战---1
    51. N皇后
    拟合算法
    216. 组合总和 III
    打印心性
    指针
    第五天
    循环 和 宏
  • 原文地址:https://www.cnblogs.com/Zzqf/p/12691997.html
Copyright © 2020-2023  润新知