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;
}