HDU 6166 二進位制分組
阿新 • • 發佈:2018-12-01
題意 :有向圖,點集內的任意兩點最短路徑的最短值
思路 :很有意思的題目,直接兩兩列舉肯定不可以,這裡考慮二進位制分組,這樣只需要分18次就能使得一次分組時最優解在兩個不同的集合裡面。
接下來就是分組後縮點一下跑他20次最短路。。很有意思!!
PS vector被卡了常數。。。
程式碼:
#include<bits/stdc++.h> using namespace std; #define X first #define Y second #define PB push_back #define MP make_pair #define MEM(x,y) memset(x,y,sizeof(x)); #define bug(x) cout<<"bug"<<x<<endl; typedef long long ll; typedef pair<int,int> pii; using namespace std; const ll INF=1e18; const int MAXN=200100; 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 to,next,val; }edge[MAXN]; int head[MAXN],tot; bool vis[MAXN]; ll dist[MAXN]; void init(){ tot = 0;memset(head,-1,sizeof(head)); } void Dijkstra(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 = head[u];i != -1;i = edge[i].next){ int v = edge[i].to; int cost=edge[i].val; 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){ edge[tot].to = v; edge[tot].val = w; edge[tot].next = head[u]; head[u] = tot++; } bool st[MAXN]; int X[MAXN],Y[MAXN],Z[MAXN]; int main(){ int t,n,m,k,u,v,x,w; scanf("%d",&t); for(int ca=1;ca<=t;ca++){ ll ans=INF; MEM(st,0); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++)scanf("%d%d%d",&X[i],&Y[i],&Z[i]); scanf("%d",&k); for(int i=0;i<k;i++) scanf("%d",&x),st[x]=1; for(int ii=0;ii<=17;++ii){ int i=r[ii]; init(); for(int j=1;j<=m;++j){ u=X[j];v=Y[j];w=Z[j]; int two=1<<i; if(st[u]&&(u&two)) u=n+1; else if(st[u]&&!(u&two)) u=n+2; if(st[v]&&(v&two)) v=n+1; else if(st[v]&&!(v&two)) v=n+2; if(u!=v)addedge(u,v,w); } Dijkstra(n+2,n+1); ans=min(ans,dist[n+2]); Dijkstra(n+2,n+2); ans=min(ans,dist[n+1]); } printf("Case #%d: %lld\n",ca,ans); } }