BZOJ[Sdoi2010]大陆争霸 最短路变形

2014-11-24 07:33:25 · 作者: · 浏览: 0

Description

在一个遥远的世界里有两个国家:位于大陆西端的杰森国和位于大陆东端的 克里斯国。两个国家的人民分别信仰两个对立的神:杰森国信仰象征黑暗和毁灭 的神曾 布拉泽,而克里斯国信仰象征光明和永恒的神斯普林 布拉泽。 幻想历 8012年 1月,杰森国正式宣布曾 布拉泽是他们唯一信仰的神,同 时开始迫害在杰森国的信仰斯普林 布拉泽的克里斯国教徒。 幻想历 8012年 3月2日,位于杰森国东部小镇神谕镇的克里斯国教徒发动 起义。 幻想历 8012年 3月7日,神谕镇的起义被杰森国大军以残酷手段镇压。 幻想历 8012年 3月8日,克里斯国对杰森国宣战。由数十万大军组成的克 里斯军团开至两国边境,与杰森军团对峙。 幻想历 8012年 4月,克里斯军团攻破杰森军团防线进入神谕镇,该镇幸存 的克里斯国教徒得到解放。 战争随后进入胶着状态,旷日持久。战况惨烈,一时间枪林弹雨,硝烟弥漫, 民不聊生。 幻想历 8012年 5月12日深夜,斯普林 布拉泽降下神谕:“Trust me, earn eternal life.”克里斯军团士气大增。作为克里斯军团的主帅,你决定利用这一机 会发动奇袭,一举击败杰森国。具体地说,杰森国有 N 个城市,由 M条单向道 路连接。神谕镇是城市 1而杰森国的首都是城市 N。你只需摧毁位于杰森国首都 的曾 布拉泽大神殿,杰森国的信仰,军队还有一切就都会土崩瓦解,灰飞烟灭。 为了尽量减小己方的消耗,你决定使用自爆机器人完成这一任务。唯一的困 难是,杰森国的一部分城市有结界保护,不破坏掉结界就无法进入城市。而每个 城市的结界都是由分布在其他城市中的一些结界发生器维持的,如果想进入某个 城市,你就必须破坏掉维持这个城市结界的所有结界发生器。 现在你有无限多的自爆机器人,一旦进入了某个城市,自爆机器人可以瞬间 引爆,破坏一个目标(结界发生器,或是杰森国大神殿),当然机器人本身也会 一起被破坏。你需要知道:摧毁杰森国所需的最短时间。

Input

第一行两个正整数 N, M。 接下来 M行,每行三个正整数 ui, vi, wi,表示有一条从城市ui到城市 vi的单 向道路,自爆机器人通过这条道路需要 wi的时间。 之后 N 行,每行描述一个城市。首先是一个正整数 li,维持这个城市结界所 使用的结界发生器数目。之后li个1~N 之间的城市编号,表示每个结界发生器的 位置。如果 Li = 0,则说明该城市没有结界保护,保证L1 = 0 。

Output

仅包含一个正整数 ,击败杰森国所需的最短时间。

Sample Input

6 6
1 2 1
1 4 3
2 3 1
2 5 2
4 6 2
5 3 2
0
0
0
1 3
0
2 3 5

Sample Output

5

\

HINT

对于 20%的数据,满足 N≤15,M≤50;
对于 50%的数据,满足 N≤500,M≤6,000;
对于 100%的数据,满足 N≤3,000,M≤70,000,1≤wi≤108

输入数据保证一定有解,且不会存在维持某个城市结界的结界发生器在这个
城市内部。
连接两个城市的道路可能不止一条, 也可能存在一个城市自己到自己的道路。< http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KCjxicj4KPC9oMj4KPGJyPgoKPGJyPgoK1eK1wMziysfSu7XAtPjP3tbGtcTX7rbMwrfOyszio6zK18/I0OjSqrTdu9m52M+1zby1xMjrsd+21NOmtcS147LFxNy1vcv7o6zG5LTOv8nS1M2syrHX37bguPa146GjCsrXz8i/vMLHzqy7pMG9uPbK/dfpo6zSu7j2ysfU3cfSsru/vMLHtbHHsLXjtcTI67HftcTX7rbMvuDA62hbXaOs0ru49srH1ebKtbXEvuDA62Rpc1tdo6y/vMLH08NzcGZh1/ajrMO/tM64/NDCwcvSu7j2tePV5sq1tcTX7rbMvuDA66Osvs29q8v7vNPI67bTwdCjrL+0yse38cTcuPzQwsbky/u1xLXjo6y21NPaw7/Su7TOuPzQwqOstrzSqsmo0rux6b+0y/vL+dPQx7DH/bXE1+62zL7gwOujrMv50tTKsbzkuLTU07bIvs3Kx08oTl4zKdfz09Khowo8YnI+Cgo8cHJlIGNsYXNzPQ=="brush:java;">#include #include #include #include #include #include using namespace std; int get_int(){ int x=0;char c;int t=0; for (c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar()); if (c=='-'){t=1;c=getchar();} for (;c>='0'&&c<='9';c=getchar()){x*=10;x+=c-48;} if (t) x=-x;return x; } const int maxn=3050,maxm=70050; int n,m; long long inf; int heap[maxn][maxn],tal[maxn]; int stay[maxn]; long long d[maxn],f[maxn]; int first[maxn],to[maxm],next[maxm],w[maxm],size; void put(int x,int y,int ww) { size++; next[size]=first[x]; first[x]=size; to[size]=y; w[size]=ww; } int first_[maxn],to_[maxn*maxn/2],next_[maxn*maxn/2]; void put_(int x,int y) { size++; next_[size]=first_[x]; first_[x]=size; to_[size]=y; } void init() { inf=(1<<29); inf=inf*inf; n=get_int(),m=get_int(); for (int i=1;i<=n;i++) f[i]=d[i]=inf; d[1]=0; f[1]=0; for (int i=1;i<=m;i++) { int x=get_int(),y=get_int(),ww=get_int(); if (x!=y) put(x,y,ww); } size=0; for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) stay[j]=0; for (int j=get_int();j;j--) {int x=get_int(); if (!stay[x]); { tal[i]++; heap[i][tal[i]]=x; stay[x]=1; //up(i,tal[i]); put_(x,i); } } } } int line[maxn*5],mod=maxn*5-50; bool upmin(long long &x,long long y) { if (y x) {x=y;return true;} return false; } bool ban(int v) { long long ans=f[v]; f[v]=d[v]; for (int i=1;i<=tal[v];i++) upmax(f[v],f[heap[v][i]]); //printf("ans = %I64d f[%d] =%I64d\n",ans,v,f[v]); if (f[v] mod) tou=1; for (int k=first[line[tou]];k;k=next[k]) { upmin(d[to[k]],f[line[tou]]+w[k]); if (ban(to[k])) {//printf(" ok ban %d\n",to[k]); if (!stay[to[k]]) { // printf(" ok %d\n",to[k]); wei++; if (wei>mod) wei=1; line[wei]=to[k]; stay[to[k]]=1; } } } for (int k=first_[line[tou]];k;k=next_[k]) {//printf("try ban %d\n",to_[k]); if (ban(to_[k])) {//printf(" ok ban %d\n",to[k]); if (!stay[to_[k]]) { //printf(" ok %d\n",to[k]); wei++; if (wei>mod) wei=1; line[wei]=to_[k]; stay[to_[k]]=1; } } } stay[line[tou]]=0; // printf("tou = %d wei =%d\n",tou,wei); // for (int i=tou;i<=wei;i++) // printf("%d ",line[i]);printf("\n"); // for (int i=1;i<=n;i++) // printf("d[%d]=%I64d f[%d]=%I64d\n",i,d[i],i,f[i]); // printf("\n"); } printf("%I64d\n",f[n]); } int main() { freopen("landcraft.in","r",stdin); freopen("landcraft.out","w",stdout); init(); spfa(); }
换个方法,用dijstra考虑呢? 每次找当前能找到的最小值,用它来进行更新,遇到max就取max,遇到min就取min,有人会说,这肯定回wa完三。 其实不然。 我们这样看,既然每次取得是最小值,那么用来更新的一定是递增的,所以对于一个点的限制只用考虑他最后一个max就够了,然后再看这个点i的dis最大的前驱到这个点这一段,我们发现,他每次只会取min,而这些用来更新的点的dis已经大于了dis[i的最大的前驱],所以取min不影响,所以总的来说,他就是个dijstra模型加一句带限制的更新。

#include
  
   
#include
   
     #include
    
      #include
     
       #include
      
        #include
       
         using namespace std; typedef long long LL; int n,m; int tot=0; int fir[200000],en[200000],nex[200000]; LL w[200000]; void ins(int a,int b,LL c){ nex[++tot]=fir[a]; fir[a]=tot; en[tot]=b; w[tot]=c; } int tot_=0; int fir_[200000],en_[200000],nex_[200000]; void ins_(int a,int b){ nex_[++tot_]=fir_[a]; fir_[a]=tot_; en_[tot_]=b; } LL dis[200000]; int rd[200000]; bool flag[200000]; int main(){ // freopen("landcraft.in","r",stdin); // freopen("landcraft.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=m;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); ins(a,b,c); } for (int i=1;i<=n;i++){ scanf("%d",&rd[i]); for (int j=1;j<=rd[i];j++){ int x; scanf("%d",&x); ins_(x,i); } } for (int i=0;i<=n;i++) dis[i]=99999999ll; dis[1]=0; for (int i=1;i<=n;i++){ int t=0; for (int j=1;j<=n;j++) if (!rd[j]&&flag[j]==false&&dis[j]