K短路。
A*+迪杰斯特拉,虽然像是spfa 但是用的迪杰斯特拉的思想,每次找到最小,然后更新。
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <set> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF 0x3ffffff struct node { int u,v,w,next; }edge[100001]; int qu[100001],qv[100001],qw[100001]; struct fnode { int g,h,u; bool operator < (fnode a)const { return a.g + a.h < h + g; } }; int first[1001]; int dis[1001]; int cnt[1001]; int in[1001]; int t,str,end,n,k; /* f[n] = h[n] + g[n]; h代表n到end的最短距离 g是在状态空间中从初始节点到n节点的实际代价 */ void CL() { t = 1; memset(first,-1,sizeof(first)); } void add(int u,int v,int w) { edge[t].u = t; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } void spfa() { int u,v,i; for(i = 1;i <= n;i ++) { dis[i] = INF; in[i] = 0; } queue<int>que; dis[str] = 0; in[str] = 1; que.push(str); while(!que.empty()) { u = que.front(); in[u] = 0; que.pop(); for(i = first[u];i != -1;i = edge[i].next) { v = edge[i].v; if(dis[v] > dis[u] + edge[i].w) { dis[v] = dis[u] + edge[i].w; if(!in[v]) { in[v] = 1; que.push(v); } } } } } int Astar() { fnode cur,nxt; int i; memset(cnt,0,sizeof(cnt)); priority_queue <fnode> que; cur.u = str; cur.g = 0; cur.h = dis[cur.u]; que.push(cur); while(!que.empty()) { cur = que.top(); que.pop(); cnt[cur.u] ++; if(cnt[cur.u] > k) continue; if(cnt[end] == k) { return cur.g; } for(i = first[cur.u];i != -1;i = edge[i].next) { nxt.u = edge[i].v; nxt.g = cur.g + edge[i].w; nxt.h = dis[edge[i].v]; que.push(nxt); } } return -1; } int main() { int i,m,S,T; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 0;i < m;i ++) { scanf("%d%d%d",&qu[i],&qv[i],&qw[i]); add(qv[i],qu[i],qw[i]); } scanf("%d%d%d",&S,&T,&k); if(S == T)k ++;// str = T; end = S; spfa(); CL(); for(i = 0;i < m;i ++) { add(qu[i],qv[i],qw[i]); } str = S; end = T; printf("%d\n",Astar()); } return 0; }
有意思的一题,把求和式子转换一下,就是最短路了。
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <set> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF 20000000000LL #define LL long long struct node { int u,v,w,next; }edge[210000]; int first[50100]; LL dis[50100]; int in[50100]; int wgt[50100]; int t,n; void CL() { t = 1; memset(first,-1,sizeof(first)); } void add(int u,int v,int w) { edge[t].u = u; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } LL spfa() { int i,u,v; for(i = 1;i <= n;i ++) { dis[i] = INF; in[i] = 0; } queue<int> que; in[1] = 1; dis[1] = 0; que.push(1); while(!que.empty()) { u = que.front(); in[u] = 0; que.pop(); for(i = first[u];i != -1;i = edge[i].next) { v = edge[i].v; if(dis[v] > dis[u] + edge[i].w) { dis[v] = dis[u] + edge[i].w; if(!in[v]) { in[v] = 1; que.push(v); } } } } LL ans = 0; for(i = 1;i <= n;i ++) { if(dis[i] == INF) return -1; ans += dis[i]*wgt[i]; } return ans; } int main() { int cas,i,m; scanf("%d",&cas); while(cas--) { CL(); scanf("%d%d",&n,&m); for(i = 1;i <= n;i ++) scanf("%d",&wgt[i]); for(i = 0;i < m;i ++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } LL ans = spfa(); if(ans == -1) printf("No Answer\n"); else printf("%lld\n",ans); } return 0; }
最短路条数+次短路条数,spfa形式的迪杰斯特拉,不是很懂此题的思路。
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <set> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF 0x3ffffff struct node { int u,v,w,next; }edge[100000]; int first[10000]; int dis[10000][2]; int cnt[10000][2]; int in[10000][2]; int n,t,S,T; struct fnode { int u,w,k; bool operator < (fnode a)const { return a.w < w; } }; void CL() { t = 1; memset(first,-1,sizeof(first)); } void add(int u,int v,int w) { edge[t].u = u; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } int spfa() { int i,j,u,v; fnode cur,nxt; for(i = 1;i <= n;i ++) { for(j = 0;j < 2;j ++) { dis[i][j] = INF; cnt[i][j] = 0; in[i][j] = 0; } } dis[S][0] = 0; cnt[S][0] = 1; cnt[S][1] = 1; priority_queue<fnode>que; cur.u = S; cur.w = 0; cur.k = 0; que.push(cur); while(!que.empty()) { cur = que.top(); que.pop(); u = cur.u; if(in[u][cur.k]) continue; in[u][cur.k] = 1; for(i = first[u];i != -1;i = edge[i].next) { v = edge[i].v; if(dis[v][0] > cur.w + edge[i].w) { dis[v][1] = dis[v][0]; cnt[v][1] = cnt[v][0]; dis[v][0] = cur.w + edge[i].w; cnt[v][0] = cnt[u][cur.k]; nxt.u = v; nxt.w = dis[v][0]; nxt.k = 0; que.push(nxt); nxt.u = v; nxt.w = dis[v][1]; nxt.k = 1; que.push(nxt); } else if(dis[v][0] == cur.w + edge[i].w) { cnt[v][0] += cnt[u][cur.k]; } else if(dis[v][1] > cur.w + edge[i].w) { dis[v][1] = cur.w + edge[i].w; cnt[v][1] = cnt[u][cur.k]; nxt.u = v; nxt.w = dis[v][1]; nxt.k = 1; que.push(nxt); } else if(dis[v][1] == cur.w + edge[i].w) { cnt[v][1] += cnt[u][cur.k]; } } } if(dis[T][0] == dis[T][1]-1) return cnt[T][0] + cnt[T][1]; else return cnt[T][0]; } int main() { int cas,m,i,u,v,w; scanf("%d",&cas); while(cas--) { CL(); scanf("%d%d",&n,&m); for(i = 0;i < m;i ++) { scanf("%d%d%d",&u,&v,&w); add(u,v,w); } scanf("%d%d",&S,&T); printf("%d\n",spfa()); } return 0; }
s 到 e的经过了n条边的最短路。
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <set> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF 1000000000 int p[301][301]; int ans[301][301]; int dis[301][301]; int tmp[301][301]; int qu[501]; int qv[501]; int qw[501]; int que[501]; int flag[1001]; int num,s,e; #define MAXN 301 void floyd(int c[][MAXN], int a[][MAXN], int b[][MAXN]) { for(int k = 1; k < num; k++) for(int i = 1; i < num; i++) for(int j = 1; j < num; j++) if(c[i][j] > a[i][k] + b[k][j]) c[i][j] = a[i][k] + b[k][j]; } void copy(int a[][MAXN], int b[][MAXN]) { for(int i = 1; i < num; i++) for(int j = 1; j < num; j++) { a[i][j] = b[i][j]; b[i][j] = INF; } } int qmod(int k) { while(k) { if(k & 1) { floyd(dis, ans, p); copy(ans, dis); } floyd(tmp, p, p); copy(p, tmp); k >>= 1; } return ans[flag[s]][flag[e]]; } int main() { int i,j,n,m,u,v,w; scanf("%d%d%d%d",&n,&m,&s,&e); for(i = 1; i <= 300; i ++) { for(j = 1; j <= 300; j ++) { p[i][j] = INF; ans[i][j] = INF; dis[i][j] = INF; tmp[i][j] = INF; } ans[i][i] = 0;//注意这里 } num = 1; for(i = 0; i < m; i ++) { scanf("%d%d%d",&qw[i],&qu[i],&qv[i]); if(flag[qu[i]] == 0) flag[qu[i]] = num++; if(flag[qv[i]] == 0) flag[qv[i]] = num++; u = flag[qu[i]]; v = flag[qv[i]]; w = qw[i]; p[u][v] = min(p[u][v],w); p[v][u] = min(p[v][u],w); } printf("%d\n",qmod(n)); }
最优比率生成环
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <set> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF 0x3f3f3f3f #define eps 1e-3 struct node { int u,v,next; double w; }edge[10000]; int p[1001]; int first[1001]; double dis[1001]; int in[1001]; int num[1001]; int t,n; void CL() { t = 1; memset(first,-1,sizeof(first)); } void add(int u,int v,int w) { edge[t].u = u; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } int spfa(double r) { int i,u,v; double w; for(i = 1;i <= n;i ++) { dis[i] = INF; num[i] = 0; in[i] = 0; } dis[1] = 0; in[1] = 1; queue<int>que; que.push(1); while(!que.empty()) { u = que.front(); que.pop(); in[u] = 0; for(i = first[u];i != -1;i = edge[i].next) { v = edge[i].v; w = -p[v] + r*edge[i].w; if(dis[v] > dis[u] + w) { dis[v] = dis[u] + w; if(!in[v]) { in[v] = 1; num[v] ++; if(num[v] > n) return 1; que.push(v); } } } } return 0; } int main() { int m,i,u,v; double w; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 1;i <= n;i ++) scanf("%d",&p[i]); for(i = 1;i <= m;i ++) { scanf("%d%d%lf",&u,&v,&w); add(u,v,w); } double str,end,mid; str = 0; end = 10000000; while(str+eps < end) { mid = (str + end)/2; if(spfa(mid)) str = mid; else end = mid; } printf("%.2lf\n",str); } return 0; }
二维的spfa,这题主要是会超时,首先转移有两种,加1单位的油或者 走向下个城市,这样会spfa的比较快,然后写成spfa形式的迪杰斯特拉,就可AC。
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <set> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF 0x3f3f3f3f #define eps 1e-3 struct node { int u,v,w,next; } edge[30000]; struct city { int u,c,w; bool operator < (city a)const { return a.w < w; } }; int t,n; int first[1001]; int p[1001]; int dis[1001][101]; int in[1001][101]; int s,e,c; void CL() { t = 1; memset(first,-1,sizeof(first)); } void add(int u,int v,int w) { edge[t].u = u; edge[t].v = v; edge[t].w = w; edge[t].next = first[u]; first[u] = t ++; } int spfa() { int i,j,u,v,tc; city cur,nxt; for(i = 0; i < n; i ++) { for(j = 0; j <= c; j ++) { dis[i][j] = INF; in[i][j] = 0; } } priority_queue<city>que; cur.u = s; cur.c = 0; cur.w = 0; dis[cur.u][cur.c] = 0; in[s][0] = 1; que.push(cur); while(!que.empty()) { cur = que.top(); u = cur.u; tc = cur.c; que.pop(); if(u == e) return cur.w; in[u][tc] = 0; if(tc + 1 <= c)//加油 { if(dis[u][tc+1] > dis[u][tc] + p[u]) { dis[u][tc+1] = dis[u][tc] + p[u]; v = u; j = tc+1; nxt.u = v; nxt.c = j; nxt.w = dis[v][j]; que.push(nxt); } } for(i = first[u]; i != -1; i = edge[i].next) { v = edge[i].v; if(tc >= edge[i].w)//走点 { j = tc-edge[i].w; if(dis[v][j] > dis[u][tc]) { dis[v][j] = dis[u][tc]; nxt.u = v; nxt.c = j; nxt.w = dis[v][j]; que.push(nxt); } } } } return -1; } int main() { int m,i,q; while(scanf("%d%d",&n,&m)!=EOF) { CL(); for(i = 0; i < n; i ++) scanf("%d",&p[i]); for(i = 0; i < m; i ++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } scanf("%d",&q); while(q--) { scanf("%d%d%d",&c,&s,&e); int temp = spfa(); if(temp == -1) printf("impossible\n"); else printf("%d\n",temp); } } return 0; }
最优比率生成树
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <string> #include <set> #include <map> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF 100000000 #define eps 1e-4 struct node { double x,y,z; double w; }p[1001]; double low[1001]; int o[1001],n; double fun(int u,int v,double mid) { double l,c; l = sqrt((p[u].x-p[v].x)*(p[u].x-p[v].x) + (p[u].y-p[v].y)*(p[u].y-p[v].y)); c = fabs(p[u].z-p[v].z); return c-mid*l; } double judge(double mid) { int i,j,k; double ans = 0,minz; for(i = 1;i <= n;i ++) { low[i] = INF; o[i] = 0; } low[1] = 0; for(i = 1;i <= n;i ++) { minz = INF; for(j = 1;j <= n;j ++) { if(!o[j]&&minz > low[j]) { minz = low[j]; k = j; } } o[k] = 1; ans += minz; for(j = 1;j <= n;j ++) { double temp = fun(k,j,mid); if(!o[j]&&low[j] > temp) { low[j] = temp; } } } return ans; } int main() { int i; double str,end,mid; while(scanf("%d",&n)!=EOF) { if(n == 0) break; for(i = 1;i <= n;i ++) { scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z); } str = 0; end = 100000; while(str + eps < end) { mid = (str + end)/2; if(judge(mid) <= 0) end = mid; else str = mid; } printf("%.3lf\n",str); } return 0; }
最小树形图,抄的模板,把序号 改成从1开始不知道为什么过不了。
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <string> #include <set> #include <map> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF ~0u>>1 #define N 1001 #define eps 1e-8 int t; struct node { int u,v; double w; } edge[100000]; struct point { double x,y; } p[N]; double in[N]; int pre[N]; int vis[N]; int id[N]; int n,m; double dis(point a,point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double Directed_MST(int root) { double ret = 0; int i, u, v; while(true) { for(i = 0; i < n; i ++) in[i] = INF; for(i = 1;i <= m;i ++) { u = edge[i].u; v = edge[i].v; if(edge[i].w < in[v] && u != v) { in[v] = edge[i].w; pre[v] = u; } } for(i = 0;i < n;i ++) //如果存在除root以外的孤立点,则不存在最小树形图 { if(i == root) continue; if(in[i] == INF) return -1; } int cnt = 0; memset(id,-1,sizeof(id)); memset(vis,-1,sizeof(vis)); in[root] = 0; for(i = 0;i < n;i ++) //找环 { ret += in[i]; int v = i; while(vis[v] != i && id[v] == -1 && v != root) { vis[v] = i; v = pre[v]; } if(v != root && id[v] == -1) //重新标号 { for(u = pre[v]; u != v; u = pre[u]) { id[u] = cnt; } id[v] = cnt++; } } if(cnt == 0) break; for(i = 0;i < n;i ++) { if(id[i] == -1) id[i] = cnt++; //重新标号 } for(i = 1;i <= m;i ++) //更新其他点到环的距离 { v = edge[i].v; edge[i].u = id[edge[i].u]; edge[i].v = id[edge[i].v]; if(edge[i].u != edge[i].v) { edge[i].w -= in[v]; } } n = cnt; root = id[root]; } return ret; } int main() { int i,u,v; double ans; while(scanf("%d%d",&n,&m)!=EOF) { for(i = 0; i < n; i ++) { scanf("%lf%lf",&p[i].x,&p[i].y); } for(i = 1; i <= m; i ++) { scanf("%d%d",&u,&v); u --; v --; edge[i].u = u; edge[i].v = v; edge[i].w = dis(p[u],p[v]); } ans = Directed_MST(0); if(ans == -1) printf("poor snoopy\n"); else printf("%.2f\n",ans); } return 0; }
暴力...
#include <iostream> #include <cstdio> #include <string> #include <algorithm> #include <stdlib.h> #include <vector> #include <cmath> #include <queue> #include <string> #include <set> #include <map> #include <stack> #include <queue> #include <cstring> using namespace std; #define INF 0x7ffffff struct node { int u,v,w; }edge[10001]; int o[101]; int num; bool cmp(node a,node b) { return a.w < b.w; } int find(int x) { while(x != o[x]) x = o[x]; return x; } void merge(int x,int y) { x = find(x); y = find(y); if(o[x] != y) { num ++; o[x] = y; } } int main() { int u,v,i,j,w,ans,n,m; while(scanf("%d%d",&n,&m)!=EOF) { if(n == 0&&m == 0) break; for(i = 0;i < m;i ++) scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); sort(edge,edge+m,cmp); ans = INF; for(i = 0;i < m;i ++) { for(j = 1;j <= n;j ++) o[j] = j; num = 0; for(j = i;j < m;j ++) { u = edge[j].u; v = edge[j].v; w = edge[j].w; if(w - edge[i].w > ans) break; merge(u,v); if(num == n-1) { ans = min(ans,w-edge[i].w); break; } } } if(ans == INF) printf("-1\n"); else printf("%d\n",ans); } return 0; }