1. 程式人生 > >派對選址

派對選址

過去的 ssi str 不存在 數據規模 技術 sap set 時有

派對選址
(party.pas/c/cpp)
【題目描述】
在2022年,scu_acmers決定舉行一個聚會,並且大多數老 scu_acmers隊員已經收到了邀請函,包
括隊員 onmylove,tanlinghang和zsasuke(scu_isap隊的老隊員)。
從 scu畢業已經 10年了,現在他們住在不同的城市。他們都非常傲慢,都認為在所有 scu_acmers
隊員中,自己才是最擅長跑步的人。為了證明這一點,他們都決定花上幾天時間跑向目的地(聚會所舉
辦的城市),並且為了節省體力,他們每個人都會選擇最短的路線前往(可能存在多條最短路線,在這種
情況下,他們會隨機選擇其中的一條)。但是這會導致一系列問題:他們會偶然停下來休息,並且他們
一旦在同一條路上相遇,他們會停止前進,開始爭吵誰才是最擅長跑步的人,徹底錯過聚會。
Scu 的領導都是考慮周到的人,他們不想讓任何一個人錯過聚會,因此他們想要選擇一個合適的聚
會城市,使得 scu_isap的隊員們不會在中途相遇。但是他們都很忙,所以這個任務就交給你了。
【輸入文件】
第一行兩個正整數 N 和M,表示城市個數和道路條數(onmylove 住在城市 1,tanlinghang 住在城市 2,
zsasuke 住在城市 3),接下來 M行,每行包含三個正整數a,b,c(1≤a,b≤N,1≤c≤10,b≠a,並且任意
兩個城市之間至多只有一條道路直接相連),表示從a到b 要花費 c天,從b到 a要花費 c天。
【輸出文件】
如果不存在這樣的城市,輸出僅一行”impossible”(不含引號),否則,第一行輸出一個數 P,表示有
P 個城市滿足要求,接下來一行,P個用空格隔開的數,表示滿足條件的城市編號(升序輸出)。
【樣例輸入】
5 5
1 5 2
4 5 2
5 2 3
2 4 5
3 4 1

【樣例輸出】
1
5

【樣例解釋】
我們不能選擇 4 號城市。假如我們選擇 4 號城市,那麽,onmylove 的路線是1-5-4;tanlinghang 的是
2-5-4或2-4;如果tanlinghang選擇2-5-4,他將與onmylove在5和4之間的道路上相遇,然後爭吵。

【數據規模】
對於10%的數據: 3≤N≤5;1≤M≤10;
對於100%的數據:3≤N≤3000;1≤M≤200000;

派對選址
題目看起來很難的樣子,真心不會做。。。
但是,題目中有個突破口——某個人有多條路徑可走,而且不能和別人的最短路徑有交集——看似使題目變得很難,實際上,要是有交集的話,那麽從交點延伸過去的,以這條路為中間路徑的某兩點之間的最短路上的點(在交點之後)肯定不可行,例子見下——

技術分享
假設a在1,b在2,c在3。
b和c在4的時候就有了交集,說明在6,7,8,9,10,5,1這幾個點是不可以設置Party的。
那麽剩下了2,3,4進行判斷——
2:a與c會提前相交於4,所以不行;
3:a與b會提前相交於4,所以不行;
4:可行。
(講的很辣雞,不懂沒關系)
實際上,我們可以先把從1,2,3到每個點的最短路刷出來。
那麽,我們肯定要判斷每一個點是否可行。
比如我們判斷6是否可行——
我們發現,不管點2,點3是否有其他分支,他們總是可能聚集到點4,那麽點6自然而然也就不行了。
其實,每當枚舉一個點i時,與他所有相鄰的點,比如j,如果同時有兩個人(a,b,c中的)dis[i]==dis[j]+f[j][i],說明什麽?這兩個人都有可能經過j--i這條路,那麽不就不可以了?(話說前面我在幹什麽!!!)歸根到底,某一個點是否能舉辦Party,不是看這個點,而是看與它相鄰的點和對應的邊的情況(因為如果兩個人有交點,交點卻就是終點,那也是可以的啊)。好了不說了,不然要禍害蒼靈了。。。

技術分享
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=3005,maxe=400005;
 6 int n,m,w[maxe],nxt[maxe],son[maxe],lnk[maxn];
 7 int dis[4][maxn],q[maxn];
 8 int tot=0,h,t,INF;
 9 bool vis[maxn];
10 int ans[maxn];
11 inline int read(){
12     int
x=0,f=1; char ch=getchar(); 13 while (ch<0||ch>9){if (ch==-) f=-f; ch=getchar();} 14 while (ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar(); 15 return x*f; 16 } 17 void add(int x,int y,int z){ 18 nxt[++tot]=lnk[x],son[tot]=y,w[tot]=z,lnk[x]=tot; 19 } 20 void spfa(int fl){ 21 memset(dis[fl],63,sizeof dis[fl]),INF=dis[fl][0]; 22 memset(vis,0,sizeof vis); 23 memset(q,0,sizeof q); 24 dis[fl][fl]=0,vis[fl]=1,q[1]=fl,h=0,t=1; 25 while (h!=t){ 26 h=(h+1)%maxn,vis[q[h]]=0; 27 for (int j=lnk[q[h]]; j; j=nxt[j]) 28 if (dis[fl][son[j]]>dis[fl][q[h]]+w[j]){ 29 dis[fl][son[j]]=dis[fl][q[h]]+w[j]; 30 if (!vis[son[j]]){ 31 t=(t+1)%maxn,q[t]=son[j],vis[son[j]]=1; 32 if (dis[fl][q[(h+1)%maxn]]>dis[fl][q[t]]) swap(q[(h+1)%maxn],q[t]); 33 } 34 } 35 } 36 } 37 int main(){ 38 n=read(),m=read(); 39 for (int i=1; i<=m; i++){ 40 int x=read(),y=read(),z=read(); 41 add(x,y,z),add(y,x,z); 42 } 43 spfa(1),spfa(2),spfa(3); 44 for (int i=1; i<=n; i++) 45 if (!(lnk[i]==0||dis[1][i]==INF||dis[2][i]==INF||dis[3][i]==INF)){ 46 bool flg=1; 47 for (int j=lnk[i]; j; j=nxt[j]){ 48 int pre=son[j]; 49 bool f1=dis[1][i]==dis[1][pre]+w[j],f2=dis[2][i]==dis[2][pre]+w[j],f3=dis[3][i]==dis[3][pre]+w[j]; 50 if (f1+f2+f3>=2) flg=0; 51 } 52 if (flg) ans[++ans[0]]=i; 53 } 54 if (!ans[0]) printf("impossible"); 55 else{ 56 printf("%d\n",ans[0]); 57 for (int i=1; i<=ans[0]; i++) printf("%d ",ans[i]); 58 } 59 return 0; 60 }
View Code

派對選址