CCF

10 篇文章 0 订阅

城市规划

暴力没法拿满分,也想不到有什么图论算法或树算法是可以解决这个题的,大概这时候就可以想想怎么dp了,又是树型结构,那应该考虑树形dp了。要算两两之间的距离的和,这种看上去好像是只能n方解决的,应该要注意到可能是分解成每一个部分算贡献(不然咋做呢)。考虑怎么划分集合定义dp,对于树形dp首先第一维应该是节点,第二维考虑题目的子问题,即选了多少个重要节点。dp[i][j]:在i节点下选了j个重要节点对于最终答案(最后的总和)的贡献。在分析转移,对于每个节点i都是由他的子树转移而来,在每个子树v都有min(sum[v],j)个决策(即在每个子树里都可以分别选择1到min(sum[v],j)个重要节点,并且每个选择都是互斥的)(sum[v]是在子树v里的重要点的数量)。这样就像是分组背包,每个子树是一个分组,在每个分组中选择一个决策。

#include <bits/stdc++.h>

using namespace std;
#define maxn 50010
#define inf 1e15
#define ll long long 
vector<pair<int,ll> > g[maxn];
ll dp[maxn][400];
int sum[maxn];
int vis[maxn];
int n,m,k;
void dfs(int now,int fa)
{
    for(int i=0;i<=k;i++) dp[now][i]=inf;
    dp[now][0]=0;
    if(vis[now]) sum[now]=1,dp[now][1]=0;
    for(auto x: g[now]){    //分组背包,枚举分组
        if(x.first==fa) continue;
        dfs(x.first,now);
        sum[now]+=sum[x.first];
        for(int i=min(k,sum[now]);i;i--){     //枚举体积
            for(int j=0;j<=min(i,sum[x.first]);j++){    //枚举决策
                dp[now][i]=min(dp[now][i],dp[x.first][j]+dp[now][i-j]+1ll*(k-j)*j*x.second);//添加每条从now到个子节点的边对于答案的贡献
            }
        }
    }
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=m;i++){
        int x;
        scanf("%d",&x);vis[x]=1;
    }
    for(int i=1;i<=n-1;i++){
        int u,v;ll w;
        scanf("%d %d %lld",&u,&v,&w);
        g[u].push_back(make_pair(v,w));
        g[v].push_back(make_pair(u,w));
    }
    dfs(1,-1);
    printf("%lld\n",dp[1][k]);
    return 0;
}

201903-4消息传递接口

(进程号不止0-9)

直接递归模拟照进程的过程。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
queue<string> pocess[10010];
bool wait[10010];
int T,n;
bool exc_S(int from,int to);
bool exc_R(int from,int to);
bool exc_S(int from,int to)
{
    if(wait[to]) return 0;
    while(!pocess[to].empty()){
        string tmp=pocess[to].front();
        int need=atoi(tmp.c_str()+1);
        if(wait[to]) return 0;
        if(tmp[0]=='R'&&need==from){
            pocess[to].pop();
            return 1;
        }
        else if(tmp[0]=='S'){
            wait[to]=1;
            if(exc_S(to,need)){
                pocess[to].pop();
                wait[to]=0;
            }
            else return 0;
        }
        else{
            wait[to]=1;
            if(!exc_R(to,need)) return 0;
            pocess[to].pop();
            wait[to]=0;
        }
    }
    return 0;
}
bool exc_R(int from,int to)
{
    if(wait[to]) return 0;
    while(!pocess[to].empty()){
        string tmp=pocess[to].front();
        int need=atoi(tmp.c_str()+1);
        if(wait[to]) return 0;
        if(tmp[0]=='S'&&need==from){
            pocess[to].pop();
            return 1;
        }
        else if(tmp[0]=='R'){
            wait[to]=1;
            if(exc_R(to,need)){
                pocess[to].pop();
                wait[to]=0;
            }
            else return 0;
        }
        else{
            wait[to]=1;
            if(!exc_S(to,need)) return 0;
            wait[to]=0;
            pocess[to].pop();
        }
    }
    return 0;
}
bool solve()
{
    for(int i=0;i<n;i++){
        if(wait[i]) return 0;
        while(!pocess[i].empty()){
            if(wait[i]) return 0;
            string tmp=pocess[i].front();
            int to=atoi(tmp.c_str()+1);
            wait[i]=1;
            if(tmp[0]=='S'){
                if(exc_S(i,to)) {pocess[i].pop();wait[i]=0;}
                else return 0;
            }
            else {
                if(exc_R(i,to)) {pocess[i].pop();wait[i]=0;}
                else return 0;
            }
        }
    }
    for(int i=0;i<n;i++){
        if(!pocess[i].empty()) return 0;
    }
    return 1;
}
int main()
{
    //freopen("case.txt","r",stdin);
    cin>>T>>n;
    string t;
    getline(cin,t);
    while(T--){
        memset(wait,0,sizeof wait);
        string tmp;
        for(int i=0;i<n;i++){
            while(!pocess[i].empty()) pocess[i].pop();
        }
        for(int i=0;i<n;i++){
            getline(cin,tmp);
            istringstream ss(tmp);
            string s;
            while(ss>>s){
                pocess[i].push(s);
            }
        }
        if(solve()) cout<<"0"<<'\n';
        else cout<<"1"<<'\n';
    }
    return 0;
}

201812-04 数据中心

你说这种白给的题怎么就轮不到我来考呢?

做法,kruskal生成树算法,找最后生成树最大的边即为答案。

注意边数组要开两倍,不然只能70分。

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int n,m,root;
const int maxn=50010;
const int maxm=200010;
int f[maxn];
struct Edge{
    int u,v,w;

}edge[maxm];
int tot;
int ans;
void addedge(int u,int v,int w)
{
    edge[tot].u=u;
    edge[tot].v=v;
    edge[tot++].w=w;
}
bool cmp(Edge a,Edge b)
{
    return a.w<b.w;
}
int finds(int x)
{
    if(f[x]==-1) return x;
    else return f[x]=finds(f[x]);
}
void kruskal(int n)
{
    memset(f,-1,sizeof f);
    sort(edge,edge+tot,cmp);
    int cnt=0;
    ans=0;
    for(int i=0;i<tot;i++){
        int u=edge[i].u;
        int v=edge[i].v;
        int w=edge[i].w;
        int t1=finds(u);
        int t2=finds(v);
        if(t1!=t2){
            ans=max(ans,w);
            f[t1]=t2;
            cnt++;
        }
        if(cnt==n-1) break;
    }
}
int main()
{
    //freopen("case.txt","r",stdin);
    tot=0;
    cin>>n>>m>>root;
    for(int i=0;i<m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        addedge(u,v,w);
        addedge(v,u,w);
    }
    kruskal(n);
    cout<<ans<<endl;
    return 0;
}

201712-4 行车路线

没整明白,做法都一样我就只能90分,超时了????!找不出哪里超时了,算了不搞了,考试的时候也没机会这样调试,多半直接没了,怪不得这种这么难考。(最短路SPFA算法,首先将小路做一次Floyd最短路求出各个点间的小路距离,这样就省得考虑连续走小路的处理了,转移的时候只需要考虑当前点走往下一个点是走小路还是大路,因为连续走小路的情况已经被包含在选择走小路的转移中了)

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
//#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
int n,m;
const int maxn=510;
ll d[2][maxn];
int g[2][maxn][maxn];
bool vis[maxn];
void floyed()
{
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            for(int k=1;k<=n;k++){
                if(i==k||j==k) continue;
                g[1][j][i]=g[1][i][j]=min(g[1][i][j],g[1][i][k]+g[1][k][j]);
            }
        }
    }
}
void spfa(int s)
{
    //memset(d,inf,sizeof d);
    for(int i=1;i<=n;i++) d[0][i]=d[1][i]=inf;
    d[0][s]=d[1][s]=0;
    vis[s]=1;
    queue<int> q;
    q.push(s);
    while(!q.empty()){
        int now=q.front();
        vis[now]=0;
        q.pop();
        for(int i=1;i<=n;i++){
            int flag=0;
            ll c=1ll*g[0][now][i];
            if(d[0][i]>d[0][now]+c||d[0][i]>d[1][now]+c){//走大路
                d[0][i]=min(d[0][now],d[1][now])+c;
                flag=1;
            }
            ll tp=1ll*g[1][now][i];
            if(tp!=inf&&d[1][i]>d[0][now]+tp*tp){//走小路
                d[1][i]=d[0][now]+tp*tp;
                flag=1;
            }
            if(!vis[i]&&flag){
                q.push(i);vis[i]=1;
            }
        }
    }
}
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            g[0][i][j]=g[1][i][j]=inf;
        }
    }
    for(int i=1;i<=m;i++){
        int t,u,v;int w;
        scanf("%d %d %d %d",&t,&u,&v,&w);
        if(g[t][u][v]>w){
            g[t][u][v]=g[t][v][u]=w;
        }
    }
    floyed();
    spfa(1);
    printf("%lld\n",min(d[1][n],d[0][n]));
    return 0;
}

202006-1 线性分类器

把AB点分别带入直线里判断是否同类的点都是在小于0或大于0,并且不同类的点都是要么一个大于0一个小于0。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
struct node
{
    ll x,y;
}pa[1010],pb[1010];
int cnt1,cnt2;
bool f1,f2;
int n,m;
bool check(int type,ll u0,ll u1,ll u2)
{
    if(type){
        f1=0;
        if((u0+pa[1].x*u1+pa[1].y*u2)>0) f1=1;
        for(int i=2;i<=cnt1;i++){
            ll tmp=u0+pa[i].x*u1+pa[i].y*u2;
            if(!((tmp>0&&f1)||(tmp<0&&!f1))) return false;
        }
        return true;
    }
    else{
        f2=0;
        if((u0+pb[1].x*u1+pb[1].y*u2)>0) f2=1;
        if(f1==f2) return false;
        for(int i=2;i<=cnt2;i++){
            ll tmp=u0+pb[i].x*u1+pb[i].y*u2;
            if(!((tmp>0&&f2)||(tmp<0&&!f2))) return false;
        }
        return true;
    }
}
int main()
{
    //freopen("case.txt","r",stdin);
    scanf("%d %d",&n,&m);
    cnt1=0;cnt2=0;
    for(int i=1;i<=n;i++){
        char op[2];
        ll x,y;
        scanf("%lld %lld %s",&x,&y,op);
        if(op[0]=='A') {pa[++cnt1].x=x;pa[cnt1].y=y;}
        else{
            pb[++cnt2].x=x;pb[cnt2].y=y;
        }
    }
    for(int i=1;i<=m;i++){
        ll u1,u2,u3;
        scanf("%lld %lld %lld",&u1,&u2,&u3);
        bool res=1;
        if(cnt1!=0){
            if(!check(1,u1,u2,u3)) res=0;
        }
        if(cnt2!=0){
            if(!check(0,u1,u2,u3)) res=0;
        }
        if(res) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

201909-4 推荐系统

发现第四题开始不再是图论或者什么动态规划了,开始也搞复杂模拟了。这题代码也是看了网上的题解写的,学习到的一个比较重要的思想是懒惰删除,可以注意到题目中询问操作的数量比较少,我们不需要每次有删除操作就删除,可以先保存删除信息,等到要查询的时候再删除。(发现考试时自己对这题目的理解还是有点偏差的)

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
#define inf 1000000001
#define ll long long
using namespace std;
struct Goods
{
    int type,id;
    ll score;
    Goods(int _type,int _id,ll _score):type(_type),id(_id),score(_score){}
    bool operator < (const Goods& b) const
    {
        if(b.score==score){
            if(b.type==type) return id<b.id;
            return type<b.type;
        }
        return score>b.score;
    }
};
struct del_good
{
    int type,id;
    del_good(int _type,int _id):type(_type),id(_id){}
    bool operator <(const del_good &b)const
    {
        if(type==b.type) return id<b.id;
        else return type<b.type;
    }
};
set<Goods> app;
vector<Goods> delete_good;
map<del_good,int> has_del;
vector<int> chosen[55];
int cnt[55];
int n,m;
int K[110];
int main()
{
    freopen("case.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin>>m>>n;
    for(int i=0;i<n;i++){
        int id;ll score;
        cin>>id>>score;
        for(int j=0;j<m;j++){
            app.insert(Goods(j,id,score));
        }
    }
    int opn;
    cin>>opn;
    while(opn--){
        int opt,type,commdity,score;
        cin>>opt;
        if(opt==1){
            cin>>type>>commdity>>score;
            app.insert(Goods(type,commdity,score));
        }
        else if(opt==2){
            cin>>type>>commdity;
            has_del[del_good(type,commdity)]=1;
        }
        else{
            int ksum;
            cin>>ksum;
            memset(cnt,0,sizeof cnt);
            for(int i=0;i<m;i++){
                cin>>K[i];
                chosen[i].clear();
            }
            for(set<Goods>::iterator it=app.begin();cnt[51]<ksum&&it!=app.end();){
                if(cnt[(*it).type]<K[(*it).type]){
                    if(has_del.count(del_good((*it).type,(*it).id))){
                        app.erase(it++);
                    }
                    else{
                        cnt[51]++;
                        cnt[(*it).type]++;
                        chosen[(*it).type].push_back((*it).id);
                        it++;
                    }
                }
                else it++;
            }
            for(int i=0;i<m;i++){
                if(cnt[i]==0) cout<<"-1"<<'\n';
                else{
                    for(auto x: chosen[i]) cout<<x<<" ";
                    cout<<'\n';
                }
            }
        }
    }
    return 0;
}

201809-4 再卖菜

万物皆可搜索剪枝。

但是本题我还是用了差分约束。

考虑一个比较重要而且容易忽略的关系是3*b_i<=d[i+1]-d[i-2]<=3*b_i+2,其中d[i]表示第一天的前i个店的价格总和,而给出的第二天的价格是经过了去尾法求平均得到的,所以原来第一天的第i、i-1,i+1这三个店的价格之和应符合上述的条件才行,还有一个就是d[i]-d[i-1]>=1 这个条件了。但是对于建立边的这个权值的正负和跑最短路还是最长路还是有点迷惑。十分奇怪,这又能保证了字典序最小了,只能说考试肯定想不到了。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
#define inf 1000000001
#define ll long long
using namespace std;
const int MAXN = 511;
const int INF = 0x3f3f3f3f;
const double eps = 1e-6;
const int maxn=100010;

struct Edge {
	int from, to, dist;
};
struct SPFA {
	int n, m;
	vector <Edge> edges;
	vector <int> G[MAXN];
	bool vis[MAXN];
	int d[MAXN], p[MAXN];
	int cnt[MAXN];
	void init(int n) {
		this -> n = n;
		for (int i = 0; i <=n; i++) G[i].clear();
		edges.clear();
	}
	void addedge(int from, int to, int dist) {
		edges.push_back((Edge) {from, to, dist});
		m = edges.size();
		G[from].push_back(m - 1);
	}
	void solve() {
		queue <int> q;
	    memset (vis, false, sizeof vis);
	    memset (cnt, 0, sizeof(cnt));
	    for (int i = 0; i <= n; i++)
        {
            d[i]=0;
        }
        q.push(0);
	    while (!q.empty ()) {
	        int u = q.front (); q.pop ();
	        vis[u] = false;
	        for (int i = 0; i < (int)G[u].size(); i++) {
	            Edge& e = edges[G[u][i]];
	            int v = e.to, w = e.dist;
	            if (d[v] < d[u] + w) {
	                d[v] = d[u] + w;
	                if (!vis[v]) {
	                    vis[v] = true; q.push (v);
	                }
	            }
	        }
	    }
	}
} spfa;
int b[310];
int main()
{
    //freopen("case.txt","r",stdin);
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    spfa.init(n);
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++){
        if(i==1){
            spfa.addedge(i+1,0,-(2*(b[i]+1)-1));
            spfa.addedge(0,i+1,2*b[i]);
        }
        else if(i==n){
            spfa.addedge(i,i-2,-(2*(b[i]+1)-1));
            spfa.addedge(i-2,i,2*b[i]);
        }
        else{
            spfa.addedge(i+1,i-2,-(3*(b[i]+1)-1));
            spfa.addedge(i-2,i+1,3*b[i]);
        }
    }
    for(int i=1;i<=n;i++){
        spfa.addedge(i-1,i,1);
    }
    spfa.solve();
    for(int i=1;i<=n;i++){
        cout<<(spfa.d[i]-spfa.d[i-1])<<" ";
    }
    cout<<'\n';
    return 0;
}

201709-4 通信网络

记录状态数组这些都是剪枝的技巧,有时候就会想不起来。

这题有的说tarjan缩点,想想也可以,就是有点复杂。也可以爆搜一遍所有点,记录他到达别的点的情况。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
#define inf 1000000001
#define ll long long
using namespace std;
int n,m;
bool vis[1010];
vector<int> g[1010];
int f[1010][1010];
void dfs(int start,int nex)
{
    f[start][nex]=f[nex][start]=1;
    vis[nex]=1;
    for(int i=0;i<g[nex].size();i++){
        if(vis[g[nex][i]]) continue;
        dfs(start,g[nex][i]);
    }
}

int main()
{
    //freopen("case.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
    }
    for(int i=1;i<=n;i++){
        memset(vis,0,sizeof vis);
        dfs(i,i);
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        int cnt=0;
        for(int j=1;j<=n;j++){
            if(f[i][j]) cnt++;
        }
        if(cnt==n) ans++;
    }
    cout<<ans<<'\n';
    return 0;
}

201912-4 区块链

本题参考这个大佬的博客。真的牛皮,学习到了map这个复杂的套娃。其实思路很简单,每次要查询主链的时候就在map里拿出包括查询时刻及之前的所有操作,把操作完成,再输出查询时刻的主链。日常觉得自己真菜。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;

int n,m,t,K;
vector<int> g[550];
vector<vector<int> > chains(505,{0});
map<int,unordered_map<int,array<vector<int>,2> > > actions;//这个结构可参考大佬博客的那个图
vector<int>d;
bool change_main_chain(const vector<int>& Olds,const vector<int>& News)
{
    if(News.size()>Olds.size()) return 1;
    else if(News.size()==Olds.size()&&News.back()<Olds.back()) return 1;
    else return 0;
}
void diffusion(int a,int b)    //把链向周围结点广播
{
    for(int i=0;i<g[a].size();i++){
        int now=g[a][i];
        auto& node_chain=actions[b][now][1];
        if((!node_chain.empty()&&change_main_chain(node_chain,chains[a]))||(node_chain.empty()&&change_main_chain(chains[now],chains[a])))
            node_chain=chains[a];
    }
}
void query(int a,int b)
{
    for(auto& action: actions){
        auto& nodes = action.second;
        if(action.first>b) break;
        for(auto& node: nodes){
            auto& mission= node.second;
            if(mission[0].size()!=0){    //如果有产生新的区块
                if(change_main_chain(chains[node.first],mission[1])){    //检查有无新的主链可以更新
                    chains[node.first]=mission[1];
                }
                for(auto x: mission[0]){    //更新完再产生块
                    chains[node.first].push_back(x);
                }
                //mission[1]=chains[node.first];
                diffusion(node.first,action.first+t);    //广播主链
            }
            else{
                if(change_main_chain(chains[node.first],mission[1])){
                    chains[node.first]=mission[1];
                    diffusion(node.first,action.first+t);
                }
            }
        }
    }
    actions.erase(actions.begin(),actions.upper_bound(b));    //删除已经完成的操作
    cout<<chains[a].size()<<" ";
    for(int i: chains[a]) cout<<i<<" ";
    cout<<'\n';
}
int main()
{
    //freopen("case.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    cin>>t>>K;
    while(K--){
        int a,b,c;
        cin>>a>>b;
        if(cin.get()=='\n'||cin.eof()){
            query(a,b);
        }
        else {
            cin>>c;
            actions[b][a][0].push_back(c);
        }
    }
    return 0;
}

201703-4 地铁修建

经典白给题,找最短路径的最小的最长边,迪杰斯特拉的的变形。改改松弛的条件就可以了。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 100010;
//kuangbin大佬的堆优化最短路模板
struct qnode
{
    int v,c;
    qnode(int _v=0,int _c=0):v(_v),c(_c){}
    bool operator <(const qnode &r) const
    {
        return c>r.c;
    }
};
struct Edge
{
    int v,cost;
    Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[maxn];
bool vis[maxn];
int dist[maxn];
void dij(int n,int start)
{
    memset(vis,false,sizeof vis);
    for(int i=1;i<=n;i++) dist[i]=inf;
    priority_queue<qnode> que;
    while(!que.empty()) que.pop();
    dist[start]=0;
    que.push(qnode(start,0));
    qnode tmp;
    while(!que.empty()){
        tmp=que.top();
        que.pop();
        int u=tmp.v;
        if(vis[u]) continue;
        vis[u]=true;
        for(int i=0;i<E[u].size();i++){
            int v=E[tmp.v][i].v;
            int cost=E[u][i].cost;
            if(!vis[v]&&dist[v]>max(dist[u],cost)){
                dist[v]=max(dist[u],cost);
                que.push(qnode(v,dist[v]));
            }
        }
    }
}
void addedge(int u,int v,int w)
{
    E[u].push_back(Edge(v,w));
}
int main()
{
    //freopen("case.txt","r",stdin);
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        addedge(u,v,w);
        addedge(v,u,w);
    }
    dij(n,1);
    cout<<dist[n]<<'\n';
    return 0;
}

201609-4 交通规划

先求出从首都到各个城市的最短距离,再深度搜索一次从首都到各个点所需要增加的最小花费。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 10010;
struct qnode
{
    int v,c;
    qnode(int _v=0,int _c=0):v(_v),c(_c){}
    bool operator <(const qnode &r) const
    {
        return c>r.c;
    }
};
struct Edge
{
    int v,cost;
    Edge(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge>E[maxn];
bool vis[maxn];
int dist[maxn];
int cost[maxn];
void dij(int n,int start)
{
    memset(vis,false,sizeof vis);
    for(int i=1;i<=n;i++) dist[i]=inf;
    priority_queue<qnode> que;
    while(!que.empty()) que.pop();
    dist[start]=0;
    que.push(qnode(start,0));
    qnode tmp;
    while(!que.empty()){
        tmp=que.top();
        que.pop();
        int u=tmp.v;
        if(vis[u]) continue;
        vis[u]=true;
        for(int i=0;i<E[u].size();i++){
            int v=E[tmp.v][i].v;
            int cost=E[u][i].cost;
            if(!vis[v]&&dist[v]>dist[u]+cost){
                dist[v]=dist[u]+cost;
                que.push(qnode(v,dist[v]));
            }
        }
    }
}
void addedge(int u,int v,int w)
{
    E[u].push_back(Edge(v,w));
}
void dfs(int cur,int fa,int val,int e)
{
    if(val!=dist[cur]) return;
    if(cost[cur]==-1) cost[cur]=e;
    else cost[cur]=min(cost[cur],e);
    for(auto x: E[cur]){
        int v=x.v;
        int w=x.cost;
        if(v==fa) continue;
        dfs(v,cur,val+w,w);
    }
}
int main()
{
    //freopen("case.txt","r",stdin);
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v,w;
        cin>>u>>v>>w;
        addedge(u,v,w);
        addedge(v,u,w);
    }
    dij(n,1);
    memset(cost,-1,sizeof cost);
    for(auto x:E[1]){
        int v=x.v;
        int w=x.cost;
        dfs(v,1,w,w);
    }
    int ans=0;
    for(int i=2;i<=n;i++){
        ans+=cost[i];
    }
    cout<<ans<<'\n';
    return 0;
}

201604-4 游戏

很明显了bfs找最短路就行了,标记数组多开一维用来标记时间。

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
int n,m,t;
bool vis[110][110][305];
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
struct node
{
    int x,y;
    int ti;
    node(int _x=0,int _y=0,int _ti=0):x(_x),y(_y),ti(_ti){}
};
map<pair<int,int>,pair<int,int> > mp;
int bfs()
{
    queue<node> que;
    que.push(node(1,1,0));
    vis[1][1][0]=1;
    while(!que.empty()){
        node now = que.front();
        if(now.x==n&&now.y==m) return now.ti;
        que.pop();
        node nex;
        for(int i=0;i<4;i++){
            int tx=dir[i][0]+now.x;
            int ty=dir[i][1]+now.y;
            if(tx<=0||tx>n||ty<=0||ty>m||vis[tx][ty][now.ti+1]) continue;
            nex.x=tx;nex.y=ty;
            if(tx==n&&ty==m) return now.ti+1;
            bool flag=0;
            if(mp.count(make_pair(tx,ty))){
                pair<int,int> tmp = mp[make_pair(tx,ty)];
                if(now.ti+1>=tmp.first&&now.ti+1<=tmp.second) flag=1;
                else nex.ti=now.ti+1;
            }
            else{
                nex.ti=now.ti+1;
            }
            if(flag) continue;
            vis[tx][ty][now.ti+1]=1;
            que.push(nex);
        }
    }
    return -1;
}
int main()
{
    //freopen("case.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin>>n>>m>>t;
    for(int i=1;i<=t;i++){
        int r,c,a,b;
        cin>>r>>c>>a>>b;
        mp[make_pair(r,c)]=make_pair(a,b);
    }
    cout<<bfs()<<'\n';
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值