• [APIO2017]商旅 0/1分数规划


    ~~~题面~~~

    题解:

    upd: 在洛谷上被Hack了。。。思路应该是对的,代码就别看了

    感觉有个地方还是非常妙的,就是因为在x买东西,在y卖出,就相当于直接从x走向了y,因为经过中间的城市反正也不会造成任何影响。

    所以建图就可以直接把所有城市两两连边,然后直接枚举找出使得在x买东西,在y卖出的利润最大化的物品,并将利润作为权值,(a[i])

    再floyd找出x到y的最短路径(这大概就算用到城市可以重复经过的条件了吧)作为代价,(b[i])

    接下来就和[HNOI2009]最小圈非常类似了。

    只不过这里是要找最大利润,而我们是用spfa找负环,所以可以对边权取相反数,(当然你也可以不变边权找正环)

    此外还有一个需要注意的地方,

    如果你是二分小数自然没有任何问题,

    但是如果你是二分整数就要注意判断0环了(因为答案是向下取整的),因为如果你二分小数的话,反正你会多二分几次来保证精度,所以不判断是没有什么问题的,

    但是整数不一样,所以要判断0环,方法也很简单,在dfs版spfa里面的判断条件上加上=就可以了

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define R register int
      4 #define AC 150
      5 #define ac 21000
      6 #define getchar() *o++
      7 #define inf 2139062143
      8 char READ[5001000],*o=READ;
      9 int n,m,l,mid,maxn;
     10 int buy[AC][AC*10],sale[AC][AC*10],s[AC][AC],f[AC][AC],dis[ac];
     11 int date[ac],Next[ac],Head[AC],length[ac],tot;
     12 bool vis[AC],flag;
     13 /*想了很久如何处理异地交易的问题,因为中间走过的路程会被忽略,
     14 所以实际上就相当于直接从买入地x走到了卖出地y,
     15 所以直接两两连边,因为反正可以重复经过,所以走一条边就相当于略过了中间的所有边,
     16 然后为了尽量节省时间,所以先处理出任意两点之间的最短路,因为不管怎么走收益不变,
     17 但代价变了,所以连边要连最短路,所以先floyd处理一下,再把结果连成边,
     18 不过利益不变的前提是买同一种商品,但是商品不止一种,所以还要处理出最大收益,
     19 因为地点都已经固定了,所以这个时候就只要枚举一下买哪种划得来了,
     20 标准就是买卖单个的收入就行了
     21 然后动态改一下权值就好了,dfs版spfa找负环*/
     22 inline int read()
     23 {
     24     int x=0;char c=getchar();bool z=false;
     25     while(c > '9' || c < '0') {if(c == '-') z=true; c=getchar();}
     26     while(c >= '0' && c <= '9') x=x*10+c-'0',c=getchar();
     27     if(!z) return x;
     28     else return -x;
     29 }
     30 
     31 inline void add(int f,int w)
     32 {
     33     date[++tot]=w,Next[tot]=Head[f],Head[f]=tot;
     34 }
     35 
     36 inline void upmin(int &a,int b)
     37 {
     38     if(b < a) a = b; 
     39 }
     40 
     41 inline void upmax(int &a,int b)
     42 {
     43     if(b > a) a = b;
     44 }
     45 
     46 void pre()
     47 {
     48     int a,b,c;
     49     n=read(),m=read(),l=read();
     50     memset(f,127,sizeof(f));
     51     for(R i=1;i<=n;i++)
     52     {
     53         f[i][i]=0;
     54         for(R j=1;j<=l;j++)
     55             buy[i][j]=read() , sale[i][j]=read();
     56     }
     57     for(R i=1;i<=m;i++)
     58     {
     59         a=read(),b=read(),c=read();
     60         upmin(f[a][b],c);//这里就要upmin。,,,,不然可能会被不优的边覆盖
     61     }
     62 }
     63 
     64 void init()
     65 {
     66     /*for(int i=1;i<=n;i++)
     67     {
     68         for(int j=1;j<=n;j++)
     69             printf("%d ",f[i][j]);
     70         printf("
    ");
     71     }
     72     printf("!!!
    ");*/
     73     for(R k=1;k<=n;k++)    
     74         for(R i=1;i<=n;i++)
     75         {
     76             if(f[i][k] == inf) continue;
     77             for(R j=1;j<=n;j++)
     78                 if(f[k][j] != inf) upmin(f[i][j] , f[i][k] + f[k][j]);
     79         }//怕爆了
     80     for(R i=1;i<=n;i++)//枚举起点
     81         for(R j=1;j<=n;j++)//枚举终点
     82         {
     83             if(i == j) continue;
     84             if(f[i][j] == inf) continue; 
     85             for(R k=1;k<=l;k++) //枚举买哪种
     86             {
     87                 if(sale[j][k] == -1 || buy[i][k] == -1) continue;
     88                 upmax(s[i][j],sale[j][k] - buy[i][k]);//获取利润                                                                                                                                                                                                                                                    
     89                 upmax(maxn,s[i][j] / f[i][j]);
     90             }
     91         }
     92     /*for(int i=1;i<=n;i++)
     93     {
     94         for(int j=1;j<=n;j++)
     95             printf("%d ",f[i][j]);
     96         printf("
    ");
     97     }
     98    // printf("---------------
    ");
     99     printf("
    ");
    100     for(int i=1;i<=n;i++)
    101     {
    102         for(int j=1;j<=n;j++)
    103             printf("%d ",s[i][j]);
    104         printf("
    ");
    105     }*/
    106     for(R i=1;i<=n;i++)
    107         for(R j=1;j<=n;j++)
    108         {
    109             if(i == j) continue;
    110             if(f[i][j] == inf) continue;//error,,,这里不能加上!s[i][j],虽然没有利润,但仍然可以起到连接作用
    111             add(i,j);
    112         }
    113 }
    114 
    115 void spfa(int x)
    116 {
    117     int now;
    118     vis[x]=true;
    119     for(R i=Head[x]; i ;i=Next[i])
    120     {
    121         now=date[i];
    122         if(dis[now] >= dis[x] + length[i])//找负环肯定是最短路啊
    123         {//加个等号判0环?
    124             if(vis[now]) {flag=true;break;}
    125             dis[now] = dis[x] + length[i];
    126             spfa(now);
    127         }
    128     }
    129     vis[x]=false;
    130 }
    131 
    132 bool check()
    133 {
    134     int now;
    135     flag=false;
    136     memset(dis,0,sizeof(dis));
    137     for(R i=1;i<=n;i++)
    138         for(R j=Head[i]; j ;j=Next[j])
    139         {
    140             now=date[j];
    141             length[j]=mid * f[i][now] - s[i][now];//因为要用找负环的方法找正环,所以边权取相反
    142         }//error,,是f[i][now]
    143     for(R i=1;i<=n;i++)
    144     {
    145         spfa(i);
    146         if(flag) return true;
    147     }
    148     return false;
    149 }
    150 
    151 void half()
    152 {
    153     int l=0,r=maxn;
    154     while(r - l > 1)
    155     {
    156         mid=(l + r) / 2;
    157         if(check()) l=mid;
    158         else r=mid;
    159     }
    160     if(r > l)
    161     {
    162         mid=r;
    163         if(check()) printf("%d
    ",r);
    164         else printf("%d
    ",l);
    165     }
    166     else printf("%d
    ",l);
    167 }
    168 
    169 int main()
    170 {
    171 //    freopen("in.in","r",stdin);
    172     fread(READ,1,5000000,stdin);
    173     pre();
    174     init();
    175     half();
    176 //    fclose(stdin);
    177     return 0;
    178 }
  • 相关阅读:
    Linux下搭建DNS服务器
    Linux下安装Oracle客户端
    CentOS下配置LVM和RAID
    Linux下配置MySQL主从复制
    Linux下二进制文件安装MySQL
    不偏移的天地图地图服务
    Lucene
    Arcpy处理修改shapefile FeatureClass 线要素坐标
    使用ArcGIS实现WGS84经纬度坐标到北京54高斯投影坐标的转换
    ArcGIS自定义坐标变换中的方法说明
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9143677.html
Copyright © 2020-2023  润新知