训练日记2019.11.9 北美icpc区域赛最短路

2019.11.9 星期六
一周没写东西了,不是偷懒,这一周的事情真的是太多了,从周一开始我就没停下来过,写2212作业,然后3251,之后是3035,2420又考期中,几乎是每一课的作业刚写完,就得紧接着写下一份,休息?哪能啊,一休息好了,就别想按时交上作业,我今天写完这个就撤了,是该好好休息一下了,嗯。

今天写了2810作业,有一点不太会回去找老师同学问问,突然又想起来自己在高中按计算器的时候了,周三下午开好假条,听完Nikki的课,然后回宿舍锻炼,锻炼完之后跑到食堂买个糯米团和大烧卖,紫薯炒年糕,买碗双皮奶,回去吃完继续上cs课。不过这样的日子真的离我越来越远了,等到我真的从大学毕业,我想我再也没有理由回去这个地方了。不过寒假还是可以回去看看,这届新高三是我们那届的尾巴了,据说挺强的,回去和老师同学见见面,看看今年能不能把郑外干下去,不知不觉得已经这么久了,18届的申请也已经是一个遥远的传说了,一路走来,不得不说我们这一届千禧年出生的没给谁丢过脸,高中,我们是上下三届最能打的一届,干掉郑外的是我们,出北大复旦的也是我们,大学,我们这届组成了迄今为止最为强悍的一届,1101,2201我们都是最难的,随之而来的是naq的爆炸输出,队均6道,这在其他时候敢都不敢想。那一届的事情想来没多少人知道了,郑州上空的传说,那就让他成为永远的传说吧。继续下去,这将是一片更为广阔的天地。
题目:Mid Central ICPC regional 第F题 Dragon Ball I (传送门)

今天把困扰了好久的最短路做出来了,事实证明最短路就最短路,别老是突发奇想搞些莫名其妙的。这道题一开始我以为是普通的最短路,搜索问题,然后就上了floyd,吃了上次的亏,直接开了long long,然而调试的时候却发现,woc,20w个点,floyd是要爆内存的,然后只能从dijkstra入手了,仔细读题,发现是个无向图的有限生成树的问题,对了也可以说这是tsp问题,事实上uw的大佬就是这样写的,不过他的代码我看了一下,搞oi的大佬属实rbq,看不太懂,所以我还是自己思考吧,一共只有7个点,而且可能会重复,一次经过城市可以带走的龙珠数量没上限,那就用set去掉重复的,这样的话,那就把所有点按着顺序遍历一遍做dijkstra就ok了。样例通过,但是wa掉了,我突然发现不能排除从某一点开始比按读入顺序花费要少的情况,那这就尴尬了,最小生成树呗,但是20w条边用kruskal还是prim显然是不太行,而且操作起来有非常大的难度,我就想,那要不就用暴力dfs枚举起始点做深搜吧。最多7 * 7就49次dijkstra,最坏情况就是49nlogn,我觉得可以,就试着写了下,我用set去重,然后加入1(起始点),用回溯法dfs枚举顺序,结果果然ok了,但是提交却卡在了第五个点,我之前想着的是如果能从n到1最少,那从1-n也是如此,但是我错了,于是这道题我回去看了下。结果发现了一个重大失误,我的有个地方写错了,还是过了4个case(这数据怎么造的?),改完之后反倒还不如不改,第二个测试点就wa了。饿,陷入了停滞。

不过今天打算重构一下代码,用spfa替代了dijkstra,然后dfs的递归我也修改了下顺序,突然想到,我在set里添加1点简直是画蛇添足!根本不用加,枚举的时候直接计算就好了,结果是可以过了,但是第二个点tle了。。。多难兴邦啊。我想到,如果做dfs会产生大量的斐波那契似的重复计算,那为何不用map和pair事先预处理一下呢?说干就干,结果用map实现做好最短路之后的效率果然大幅提升,顺利过了这道题,顺带提一句,icpc特别喜欢出爆int的题,这次果然用对了long long。总之,终于过了,ac代码如下,这么多wa点,果然是没有准备的队伍估计很难过咯,题解已经发给了兄弟队伍,我先撤了。
ac代码如下

#include <bits/stdc++.h>
using namespace std;
#define limit 200000 + 5//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-6
#define ff(a) printf("%d\n",a );
#define MOD 1e9 + 7
typedef long long ll;
void read(int &x){
    char ch = getchar();x = 0;
    for (; ch < '0' || ch > '9'; ch = getchar());
    for (; ch >='0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
}//快读
int vis[limit];
int n,m;
struct edge{
    int to;
    ll weight;
    edge(int tt, ll ww):to(tt) , weight(ww){}
    bool operator<(const edge &rhs)const{
        return weight > rhs.weight;
    }
};
map<pair<int, int> , ll>costt;//存数组
ll dist[limit];
vector<vector<edge> >v;
ll dijkstra(int s, int e){
    for(int i = 0 ; i <= n + 1 ; ++i){
        vis[i] = 0;//没找过
        dist[i] = inf;
    }
    queue<int>q;
    dist[s] = 0;
    vis[s] = 1;
    q.push(s);
    while(!q.empty()){
        int vs = q.front();
        q.pop();
        vis[vs] = 0;
        for(edge it : v[vs]){
            int ve = it.to;
            ll weight = it.weight;
            if(dist[vs] != inf && dist[vs] + weight < dist[ve]){
                dist[ve] = dist[vs] + weight;
                if(!vis[ve]){
                    vis[ve] = 1;
                    q.push(ve);
                }
            }
        }
    }
    return dist[e];
}
vector<int>citi;
int visited[17 + 5];
ll dfs(int cur,int step ,ll cost){
    if(step >= citi.size()) return cost;
    ll ans = inf;
    for(int i = 0 ; i < citi.size() ; ++i){
        if(!visited[i]){
            ll res = costt[make_pair(cur, citi[i])];
            visited[i] = 1;
            ans = min(ans, dfs(citi[i] , step + 1, cost + res));
            visited[i] = 0;
        }
    }
    return ans;
}
void add(int a, int b ,ll w){
    v[a].push_back(edge(b,w));
    v[b].push_back(edge(a,w));
}
int main(){
    //freopen("C:\\Users\\administrator01\\CLionProjects\\untitled14\\data.txt", "rt" , stdin);
    scanf("%d%d", &n , &m);
    v.clear();
    v.resize(n + 1);
    citi.clear();
    for(int i = 0 ; i < m ; ++i){
        int a, b;
        ll w;
        scanf("%d%d%lld" , &a, &b , &w);
        add(a,b,w);
    }
    set<int>c;
    for(int i = 0 ; i < 7 ; ++i){
        int ss;
        scanf("%d" , &ss);
        c.insert(ss);
    }
    //c.insert(1);
    for(auto it = c.begin() ; it != c.end() ; ++it){
        citi.push_back(*it);
    }
    ll ans = inf;
    costt.clear();
    for(int i = 0 ; i < citi.size() ; ++i){
        for(int j = 0 ; j < citi.size() ; ++j){
            if(i == j){
                costt[make_pair(citi[i],citi[j])] = 0;//自己到自己
            }else{
                ll c = dijkstra(citi[i], citi[j]);
                costt[make_pair(citi[i],citi[j])] = c;//costt[make_pair(citi[j],citi[i])] = c;
            }
        }
    }//记忆化搜索
    memset(visited, 0 , sizeof(visited));

    for (int i = 0; i < citi.size(); ++i) {
        ll res = dijkstra(1, citi[i]);
        ans = min(ans, dfs(citi[i], 0 , 0) + res);
    }
    printf("%lld", ans != inf ? ans: -1);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值