【AT2434】JOI 公園 (JOI Park) 最短路+贪心
生活随笔
收集整理的這篇文章主要介紹了
【AT2434】JOI 公園 (JOI Park) 最短路+贪心
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題解
我的歪解
我首先想的是分治,我想二分肯定不行,因?yàn)樗菦]有單調(diào)性的。
我想了一下感覺它的大部分?jǐn)?shù)據(jù)應(yīng)該是有凸性的(例如\(y=x^2\)的函數(shù)圖像),所以可以三分。
下面是我的三分代碼(騙了不少分)
三分模板沒過的我居然瞎歪歪了一個(gè)三分
歪解code:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cctype> #include<queue> #define ll long long #define R register #define N 400005 #define INF 0x7fffffffffffLL using namespace std; template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x; } ll n,m,c,tot,h[N],vis[N],pd[N]; ll dist[N],sum,now_ans,now; struct bian{int u,v;ll w; }b[N]; struct node{int nex,to;ll dis; }edge[N<<1]; inline void add(R int u,R int v,R ll w){edge[++tot].nex=h[u];edge[tot].to=v;edge[tot].dis=w;h[u]=tot; } inline void spfa(R int s){for(R int i=1;i<=n;i++)dist[i]=INF;queue<int> q;q.push(s);dist[s]=0;vis[s]=1;while(!q.empty()){R int x=q.front();q.pop();vis[x]=0;for(R int i=h[x];i;i=edge[i].nex){R int xx=edge[i].to;if(dist[xx]>dist[x]+edge[i].dis){dist[xx]=dist[x]+edge[i].dis;if(!vis[xx]){vis[xx]=1;q.push(xx);}}} } } inline ll check(R ll mid){ll tot=0;for(R int i=1;i<=n;i++)pd[i]=0;for(R int i=1;i<=n;i++)if(dist[i]<=mid)pd[i]=1;for(R int i=1;i<=m;i++)if(pd[b[i].u]&&pd[b[i].v])tot+=b[i].w;return tot-mid*c;//這是你能節(jié)省的 } int main(){ read(n);read(m);read(c);for(R int i=1;i<=m;i++){read(b[i].u);read(b[i].v);read(b[i].w);add(b[i].u,b[i].v,b[i].w);add(b[i].v,b[i].u,b[i].w);sum+=b[i].w;}spfa(1);R ll l=0,r=sum;while(l<=r){R ll tmp=(r-l)/3;R ll mid1=l+tmp;R ll mid2=r-tmp;if(check(mid1)>check(mid2)) r=mid2-1;else l=mid1+1;}ll tmp=check(l),temp=check(r);if(tmp>temp)now=l,now_ans=tmp;else now=r,now_ans=temp;printf("%lld\n",sum-now_ans);return 0; }當(dāng)然了,三分本來就是一個(gè)非常好的騙分算法(也會是正解),有些題在加一些暴力,一定會有神奇的效果;
講課老師說加上暴力這道題應(yīng)該可以\(A\)掉,但懶惰的我并沒有去實(shí)踐,有興趣的可以試一試;
正解
這其實(shí)是一道經(jīng)典的最短路的一種題型。
先跑一遍\(SPFA\),處理出\(dist\)數(shù)組;
然后再利用\(dist\)數(shù)組處理出每一條邊的\(maxdis\);
將\(maxdis\)數(shù)組從小到大排序(結(jié)構(gòu)體排序);
看完圖應(yīng)該都懂了吧。
code:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cctype> #include<queue> #define ll long long #define R register #define N 800005 #define int long long #define INF 9999999999999999LL using namespace std; template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x; } ll n,m,c,tot,h[N],vis[N],pd[N],maxdis[N]; ll dist[N],sum,ans,maxsum; struct bian{int u,v,w; }b[N]; struct node{int nex,to,dis; }edge[N<<1]; struct MAX{int maxdis,id;friend bool operator < (const MAX &a,const MAX &b){return a.maxdis<b.maxdis;} }md[N]; inline void add(R int u,R int v,R int w){edge[++tot].nex=h[u];edge[tot].to=v;edge[tot].dis=w;h[u]=tot; } inline void spfa(R int s){for(R int i=1;i<=n;i++)dist[i]=INF;queue<int> q;q.push(s);dist[s]=0;vis[s]=1;while(!q.empty()){R int x=q.front();q.pop();vis[x]=0;for(R int i=h[x];i;i=edge[i].nex){R int xx=edge[i].to;if(dist[xx]>dist[x]+edge[i].dis){dist[xx]=dist[x]+edge[i].dis;if(!vis[xx]){vis[xx]=1;q.push(xx);}}} } } signed main(){ read(n);read(m);read(c);for(R int i=1;i<=m;i++){read(b[i].u);read(b[i].v);read(b[i].w);add(b[i].u,b[i].v,b[i].w);add(b[i].v,b[i].u,b[i].w);sum+=b[i].w;}spfa(1);for(R int i=1;i<=m;i++)md[i].maxdis=max(dist[b[i].u],dist[b[i].v]),md[i].id=i;sort(md+1,md+1+m);ans=sum;for(R int i=1;i<=m;i++){sum-=b[md[i].id].w;ans=min(ans,1LL*md[i].maxdis*c+sum);}printf("%lld\n",ans);return 0; }轉(zhuǎn)載于:https://www.cnblogs.com/ZAGER/p/9817918.html
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的【AT2434】JOI 公園 (JOI Park) 最短路+贪心的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: u盘中有cd驱动器怎么释放出来 如何将U
- 下一篇: 笔记本usb驱动识别不了怎么办 笔记本U