zoukankan      html  css  js  c++  java
  • [考试反思]图论专题测试:怀疑

     没写完,但是好像有人需要代码,于是先发布出来。

    回去之后记得贴排行榜。

    0+0+55.rk11.

    考场上想出了T1的三分,不确定,没有写。

    写了另一个好像靠谱点的二分,但是好像写挂了。。。

    T2没读题,又是没读题,又是没读题!!!!

    没看到它要求的是简单路径,于是简单爆9.

    T3一眼网络流,两眼不会流,三眼状压写完就走。

    最后也就T3有分。靠着一个状压苟到这个名次。。?

    T1:center

    题目大意:选择图上(点或边)上任意一点,使所有节点到这个节点最远的距离最小。$ n le 200$

    这是一堆一次函数在取max啊,显然是单谷的。

    预处理出来点对距离,然后枚举每条边在边上三分最优位置更新答案。

    但是为什么会卡参啊?0.4-0.6就过不去0.3-0.7就行,求解???

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 priority_queue<pair<int,int>>q;
     4 int dt[512][512],n,m,fir[512],l[543210],to[543210],v[543210],ec=1;double ans=1e9;
     5 void link(int a,int b,int w){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=w;}
     6 double cal(int e,double p){
     7     e<<=1;double d=0;
     8     for(int i=1;i<=n;++i)d=max(d,min(dt[to[e]][i]+p,dt[to[e|1]][i]+v[e]-p));
     9     return d;
    10 }
    11 int main(){
    12     scanf("%d%d",&n,&m);
    13     for(int i=1,a,b,w;i<=m;++i)scanf("%d%d%d",&a,&b,&w),link(a,b,w),link(b,a,w);
    14     for(int s=1;s<=n;++s){
    15         for(int t=1;t<=n;++t)dt[s][t]=1000000000;dt[s][s]=0;q.push(make_pair(0,s));
    16         while(!q.empty()){
    17             int p=q.top().second,d=-q.top().first;q.pop();if(d!=dt[s][p])continue;
    18             for(int i=fir[p];i;i=l[i])if(dt[s][to[i]]>d+v[i])q.push(make_pair(-(dt[s][to[i]]=d+v[i]),to[i]));
    19         }
    20     }
    21     for(int i=1;i<=m;++i){
    22         double l=0,r=v[i<<1];
    23         while(r-l>1e-5)if(cal(i,l*0.3+r*0.7)<cal(i,l*0.7+r*0.3))l=l*0.7+r*0.3;else r=l*0.3+r*0.7;
    24         ans=min(ans,cal(i,l));
    25     }printf("%.2lf
    ",ans);
    26 }
    View Code

    T2:escape

    题目大意:给定无向图,求严格次短简单路径且满足所有最短路上的边必须按照原方向经过。$n le 100000,m le 500000,w le 1000$

    次短路可以分成三部分,先从1号点沿着最短路走到A,然后再从A走非最短路走到B,在从B走最短路到n。

    暴力的做法时枚举AB。复杂度不可接受。

    二进制分组分为A组B组就可以做了。

    细节很多,注意1到A和B到n两部分都必须沿着最短路边定向走不然的话会导致出现非简单路径。

    例子:4 4 1 2 1 2 3 1 1 3 1 1 4 666

    然后中间一定要走非最短路,双向都不能走,不然也会导致形成非简单路径。

    在这种前提下,你走出的当然不是最短路,而又是简单路径,在考虑到所有点对后就会找到次短路。

    不要忘了在二进制分组时1为A0为B以及0为A1为B的两种情况都要考虑。

    然而这貌似不是正解,题解里只给了这种做法,好像比正解多了一个log导致过不去,而且常数也小不了。实测有且只有70分。

    在随机数据下A和B的随机某一位不同的概率为$50%$。所以我们不必都做完,只对最低的6位做然后更新答案正确率就达到$99\%$左右了,可以AC。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 1000005
     4 int n,m,fir[S],l[S],to[S],w[S],ec=1,nt[S],dt[S],dp[S],al[S],D[S],ans=1234567890,Fir[S],L[S],To[S],W[S],Ec=1;
     5 priority_queue<pair<int,int>>q;
     6 void link(int a,int b,int v){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;w[ec]=v;}
     7 void Link(int a,int b,int v){if(v>ans)return;L[++Ec]=Fir[a];Fir[a]=Ec;To[Ec]=b;W[Ec]=v;}
     8 void sch(int p){
     9     if(al[p])return;al[p]=1;
    10     for(int i=fir[p];i;i=l[i])if(dt[to[i]]==dt[p]-w[i])nt[i^1]=2,nt[i]=1,sch(to[i]);
    11 }
    12 int main(){
    13     scanf("%d%d",&n,&m);
    14     for(int i=1,x,y,v;i<=m;++i)scanf("%d%d%d",&x,&y,&v),link(x,y,v),link(y,x,v);
    15     for(int i=1;i<=n;++i)dt[i]=dp[i]=1234567890;
    16     q.push(make_pair(dt[1]=0,1));
    17     while(!q.empty()){
    18         int p=q.top().second,d=-q.top().first;q.pop();
    19         if(d!=dt[p])continue;
    20         for(int i=fir[p];i;i=l[i])if(dt[to[i]]>d+w[i])q.push(make_pair(-(dt[to[i]]=d+w[i]),to[i]));
    21     }sch(n);
    22     for(int i=1;i<=n;++i)dt[i]=1234567890;q.push(make_pair(dt[1]=0,1));
    23     while(!q.empty()){
    24         int p=q.top().second,d=-q.top().first;q.pop();
    25         if(d!=dt[p])continue;
    26         for(int i=fir[p];i;i=l[i])if(dt[to[i]]>d+w[i]&&nt[i]==2)q.push(make_pair(-(dt[to[i]]=d+w[i]),to[i]));
    27     }q.push(make_pair(dp[n]=0,n));
    28     while(!q.empty()){
    29         int p=q.top().second,d=-q.top().first;q.pop();
    30         if(d!=dp[p])continue;
    31         for(int i=fir[p];i;i=l[i])if(dp[to[i]]>d+w[i]&&nt[i]==1)q.push(make_pair(-(dp[to[i]]=d+w[i]),to[i]));
    32     }srand(time(0));
    33     for(int b=0;b<=5;b++){int x=0;
    34 X:      for(int i=0;i<=n+1;++i)Fir[i]=0,D[i]=1234567890;Ec=1;
    35         for(int i=1;i<=n;++i)if((i&1<<b)!=0^x)Link(0,i,dt[i]);else Link(i,n+1,dp[i]);
    36         for(int i=2;i<=ec;i++)if(!nt[i])Link(to[i],to[i^1],w[i]);
    37         q.push(make_pair(D[0]=0,0));
    38         while(!q.empty()){
    39             int p=q.top().second,d=-q.top().first;q.pop();
    40             if(d!=D[p])continue;
    41             for(int i=Fir[p];i;i=L[i])if(D[To[i]]>d+W[i])q.push(make_pair(-(D[To[i]]=d+W[i]),To[i]));
    42         }ans=min(ans,D[n+1]);
    43         if(!x){x=1;goto X;}
    44     }cout<<(ans==1234567890?-1:ans)<<endl;
    45 }
    View Code

    T3:chip

    题目大意:方格图,有些点必选有些点必不选,每行选的点数不超过总选点数的$frac{A}{B}$。第$i$行和第$i$列选的点数必须相同。最多选数?$n le 40$

    限制有点多有点麻烦,不难想到网络流。但是这个流量设计有点困难。

    正难则反(别问我怎么想到的%%%LNC就是了)。我们不会考虑哪些位置能放,那我们就考虑那些位置不能放。

    和《土兵占领》类似的按照行列当做点格子当做边。(但是我并不认为会做《土兵占领》的就会这道题)

    关于那个AB的限制有点恶心,但是因为这道题的数据范围很小所以其实可以直接枚举这个限制值是几。

    我们要最小化不选的数量,所以我们设其为代价,对于每个可选可不选的格子在对应行列连上一条流量1费用1的边。

    我们默认了所有的格子都要选然后再去删,所以我们先让它全选,又源点向行连边,权值为这行上所有可以选(包括必须选)的位置数。列向汇连,同理。

    这样的话,如果真的可以都选,那么答案一定是满流。

    但是我们要考虑单行选中的数量不能超过枚举的限制,所以第i行就像第i列连边费用为0流量则是枚举的限制。

    考虑它们存在的意义:如果这行的总位置数并没有达到限制,那么这0边就不会满流没有限制。

    否则,多于限制的部分就不能单纯的通过这些0边来流了,为了达到最大流所以会用与第i行或第i列相连的1边来扩展流量。

    也就是多于限制的部分必须通过1边流出,而1边表示不选,所以多于部分就适当不选来降低行列压力,从含义上理解就是对的了。

    接下来只要枚举限制跑最小费用最大流,判一下是否满流以及最大流是否满足限制即可更新答案。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define T (n<<1|1)
     4 #define N 666666
     5 #define inf 998244353
     6 int n,a,b,pc,l[N],to[N],fir[88],ans=9999,ec,v[N],w[N],q[N],d[N],al[88],iq[88],fee,lc[66],rc[66],tot;char s[44][44];
     7 void link(int a,int b,int V,int W){
     8     l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;w[ec]=+W;
     9     l[++ec]=fir[b];fir[b]=ec;to[ec]=a;v[ec]=0;w[ec]=-W;
    10 }
    11 bool SPFA(){
    12     for(int i=1;i<=T;++i)d[i]=inf,al[i]=0;
    13     for(int h=1,t=1;h<=t;iq[q[h]]=0,++h)for(int i=fir[q[h]];i;i=l[i])if(d[to[i]]>d[q[h]]+w[i]&&v[i]){
    14         if(!iq[to[i]])q[++t]=to[i],iq[to[i]]=1;
    15         d[to[i]]=d[q[h]]+w[i];
    16     }return d[T]!=inf;
    17 }
    18 int dfs(int p,int flow){
    19     if(p==T)return flow;
    20     int r=flow;al[p]=1;
    21     for(int i=fir[p];i&&r;i=l[i])if(!al[to[i]]&&d[to[i]]==d[p]+w[i]&&v[i]){
    22         int x=dfs(to[i],min(v[i],r));
    23         if(!x)d[to[i]]=inf;
    24         v[i]-=x;v[i^1]+=x;r-=x;fee+=x*w[i];
    25     }return flow-r;
    26 }
    27 int main(){
    28     scanf("%d%d%d",&n,&a,&b);
    29     for(int i=1;i<=n;++i)scanf("%s",s[i]+1);
    30     for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)if(s[i][j]!='/')lc[i]++,rc[j]++,tot++,pc+=s[i][j]=='C';
    31     for(int x=0;x<=n;++x){
    32         ec=1;for(int i=0;i<=T;++i)fir[i]=0;
    33         for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)if(s[i][j]=='.')link(i,j+n,1,1);
    34         for(int i=1;i<=n;++i)link(0,i,lc[i],0),link(i+n,T,rc[i],0),link(i,i+n,x,0);
    35         int fl=0;fee=0;
    36         while(SPFA())fl+=dfs(0,inf);
    37         if(x*b<=(fl-fee)*a&&fl==tot)ans=min(ans,fee);
    38     }if(ans==9999)puts("impossible");else cout<<tot-pc-ans<<endl;
    39 }
    View Code
  • 相关阅读:
    包路径与沙盒路径
    iOS 文件操作:沙盒(SandBox)、文件操作(FileManager)、程序包(NSBundle)
    从Swift桥接文件到Clang-LLVM
    人生•修养:知行合一
    First-class citizen
    阿里云部署SSL证书详解
    YourPHP笔记
    ThinkPHP函数详解:L方法
    robots书写说明:
    如何设置让网站禁止被爬虫收录?robots.txt
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12234343.html
Copyright © 2011-2022 走看看