• spfa处理差分约束


    差分约束是一群不等关系然后求可行解或者最小值最大值的情况 

    1.求最大值,用最短路,也就是符号要  (a)>=(b)+c  add(b,a,c)

    2.求最小值,用最长路,也就是符号要  (a)<=(b)+c  add(b,a,c)

    目录

    1.糖果(最长路)

    2.区间(最长路)

    3.排队布局(最短路)

    4.雇佣收银员(最长路)


     

    1.糖果(最长路)

     信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

    x==1 说明a==b 则a>=b且b>=a

    x==2 说明b>a 则b>=a+1

    x==3 说明a>=b

    x==4 说明a>b 则a>=b+1

    x==5 说明b>=a

    因为保证每个小孩都有一个糖果,则每个小孩>=0+1 

    1. #include
    2. using namespace std;
    3. const int N=1e5+10,M=3e5+10;
    4. typedef long long ll;
    5. int h[N],e[M],ne[M],w[M],idx;
    6. ll dist[N];
    7. int cnt[N],q[N];
    8. bool st[N];
    9. int n,k;
    10. void add(int a,int b,int c)
    11. {
    12. e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
    13. }
    14. bool spfa()
    15. {
    16. memset(dist,-0x3f,sizeof dist);
    17. int tt=1;
    18. q[0]=0;//用虚拟原点0号点更新其他点的最长路
    19. dist[0]=0;
    20. while(tt!=0)
    21. {
    22. int t=q[--tt];//用栈优化
    23. st[t]=false;
    24. for(int i=h[t];~i;i=ne[i])
    25. {
    26. int j=e[i];
    27. if(dist[j]//更新最长距离
    28. {
    29. dist[j]=dist[t]+w[i];
    30. cnt[j]=cnt[t]+1;
    31. if(cnt[j]>=n+1) return false;//假如更新了n+1次则有负环
    32. if(!st[j])
    33. {
    34. q[tt++]=j;
    35. st[j]=true;
    36. }
    37. }
    38. }
    39. }
    40. return true;//反之没负环
    41. }
    42. int main()
    43. {
    44. cin>>n>>k;
    45. memset(h,-1,sizeof h);
    46. for(int i=1;i<=n;i++) add(0,i,1);//保证每个小朋友都有一个糖果,且0这个虚拟原点可以走所有的边 i>=0+1
    47. while(k--)
    48. {
    49. int x,a,b;
    50. scanf("%d%d%d",&x,&a,&b);
    51. if(x==1) add(b,a,0),add(a,b,0);//a>=b+0且b>=a+0
    52. else if(x==2) add(a,b,1);//b>=a+1
    53. else if(x==3) add(b,a,0);//a>=b
    54. else if(x==4) add(b,a,1);//a>=b+1
    55. else add(a,b,0);//b>=a
    56. }
    57. if(spfa())//假如没负环,也就是没有小孩子有矛盾,则输出
    58. {
    59. ll res=0;
    60. for(int i=1;i<=n;i++) res+=dist[i];
    61. cout<
    62. }
    63. else puts("-1");
    64. return 0;
    65. }

    2.区间(最长路)

    362. 区间 - AcWing题库

     条件1:保证i比i-1选的数大于或者等于,则i>=i-1

    条件2:由于当前数i有;两种情况选或者不选,则i-(i-1)<=1,则(i-1)>=i-1

    条件3:题目输入,则b-(a-1)>=c,则b>=(a-1)+c

    1. #include
    2. using namespace std;
    3. const int N=50010,M=150010;
    4. int h[N],e[M],ne[M],w[M],idx;
    5. int dist[N];
    6. int q[N];
    7. bool st[N];
    8. int n;
    9. void add(int a,int b,int c)
    10. {
    11. e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
    12. }
    13. void spfa()//常规spfa
    14. {
    15. memset(dist,-0x3f,sizeof dist);
    16. int hh=0,tt=1;
    17. q[0]=0;
    18. dist[0]=0;
    19. while(hh!=tt)
    20. {
    21. int t=q[hh++];
    22. if(hh==N) hh=0;
    23. st[t]=false;
    24. for(int i=h[t];~i;i=ne[i])
    25. {
    26. int j=e[i];
    27. if(dist[j]
    28. {
    29. dist[j]=dist[t]+w[i];
    30. if(!st[j])
    31. {
    32. q[tt++]=j;
    33. if(tt==N) tt=0;
    34. st[j]=true;
    35. }
    36. }
    37. }
    38. }
    39. }
    40. int main()
    41. {
    42. scanf("%d",&n);
    43. memset(h,-1,sizeof h);
    44. for(int i=1;i<=50001;i++) add(i-1,i,0),add(i,i-1,-1);//条件1和2
    45. while(n--)
    46. {
    47. int a,b,c;
    48. scanf("%d%d%d",&a,&b,&c);
    49. if(a>b) swap(a,b);
    50. a++,b++;
    51. add(a-1,b,c);//条件3
    52. }
    53. spfa();//因为一定有解不用判断负环
    54. printf("%d\n",dist[50001]);//输出前50001个的数
    55. return 0;
    56. }

    3.排队布局(最短路)

    信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

    条件0:两两头牛距离至少为0 则i-(i-1)>=0 对应(i-1)<=i-0

    条件1:距离最多为d 则a-b<=d 对应a<=b+d

    条件2:距离最少为d 则a-b>=d 对应b<=a-d

    1. #include
    2. using namespace std;
    3. const int N=1010,M=2e4+10;
    4. int h[N],e[M],ne[M],w[M],idx;
    5. int dist[N];
    6. int q[N],cnt[N];
    7. bool st[N];
    8. int n,m1,m2;
    9. void add(int a,int b,int c)
    10. {
    11. e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
    12. }
    13. bool spfa()//常规spfa判断负环
    14. {
    15. memset(dist,0x3f,sizeof dist);//求最短路初始化最大值
    16. int hh=0,tt=1;
    17. q[0]=1;
    18. dist[1]=0;
    19. while(hh!=tt)
    20. {
    21. int t=q[hh++];
    22. if(hh==N) hh=0;
    23. st[t]=false;
    24. for(int i=h[t];~i;i=ne[i])
    25. {
    26. int j=e[i];
    27. if(dist[j]>dist[t]+w[i])//求最短路
    28. {
    29. dist[j]=dist[t]+w[i];
    30. cnt[j]=cnt[t]+1;
    31. if(cnt[j]>n) return false;
    32. if(!st[j])
    33. {
    34. q[tt++]=j;
    35. if(tt==N) tt=0;
    36. st[j]=true;
    37. }
    38. }
    39. }
    40. }
    41. return true;
    42. }
    43. int main()
    44. {
    45. cin>>n>>m1>>m2;
    46. memset(h,-1,sizeof h);
    47. for(int i=1;i<=n;i++) add(i,i-1,0);//条件0
    48. while(m1--)//条件1
    49. {
    50. int a,b,c;
    51. cin>>a>>b>>c;
    52. if(aswap(a,b);
    53. add(b,a,c);
    54. }
    55. while(m2--)//条件2
    56. {
    57. int a,b,c;
    58. cin>>a>>b>>c;
    59. if(aswap(a,b);
    60. add(a,b,-c);
    61. }
    62. if(spfa())
    63. {
    64. if(dist[n]==0x3f3f3f3f) puts("-2");//假如走不到
    65. else cout<
    66. }
    67. else puts("-1");//假如有矛盾
    68. return 0;
    69. }

    4.雇佣收银员(最长路)

    393. 雇佣收银员 - AcWing题库

     

    1. #include
    2. using namespace std;
    3. const int N=30,M=100;
    4. int dist[N];
    5. int q[N],cnt[N];
    6. bool st[N];
    7. int r[N],num[N];
    8. int n;
    9. int h[N],e[M],ne[M],w[M],idx;
    10. void add(int a,int b,int c)
    11. {
    12. e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
    13. }
    14. void built(int s24)//s24是常数也就是枚举的答案
    15. {
    16. memset(h,-1,sizeof h);
    17. idx=0;
    18. for(int i=1;i<=24;i++)
    19. {
    20. add(i-1,i,0);//si-s(i-1)>=0
    21. add(i,i-1,-num[i]);//si-s(i-1)<=num[i]
    22. }
    23. for(int i=8;i<=24;i++) add(i-8,i,r[i]);//当大于等于8时,si-s(i-8)>=ri
    24. for(int i=1;i<=7;i++) add(i+16,i,-s24+r[i]);//当小于8时,si+s(24)-s(i+16)>=ri
    25. add(0,24,s24),add(24,0,-s24);//要保证24这个点是个常数则s(24)<=s(0)+s24,s(24)>=s(0)+s24
    26. }
    27. bool spfa(int s24)//s24是常数也就是枚举的答案
    28. {
    29. built(s24);//建图
    30. //跑一遍spfa
    31. memset(dist,-0x3f,sizeof dist);
    32. memset(st,0,sizeof st);
    33. memset(cnt,0,sizeof cnt);
    34. int hh=0,tt=1;
    35. q[0]=0;
    36. dist[0]=0;
    37. st[0]=true;
    38. while(hh!=tt)
    39. {
    40. int t=q[hh++];
    41. if(hh==N) hh=0;
    42. st[t]=false;
    43. for(int i=h[t];~i;i=ne[i])
    44. {
    45. int j=e[i];
    46. if(dist[j]
    47. {
    48. dist[j]=dist[t]+w[i];
    49. cnt[j]=cnt[t]+1;
    50. if(cnt[j]>=25) return false;
    51. if(!st[j])
    52. {
    53. q[tt++]=j;
    54. if(tt==N) tt=0;
    55. st[j]=true;
    56. }
    57. }
    58. }
    59. }
    60. return true;
    61. }
    62. int main()
    63. {
    64. int T;
    65. cin>>T;
    66. while(T--)
    67. {
    68. memset(num,0,sizeof num);
    69. for(int i=1;i<=24;i++) cin>>r[i];
    70. cin>>n;
    71. for(int i=0;i
    72. {
    73. int x;
    74. cin>>x;
    75. num[x+1]++;//把0空出来当虚拟原点
    76. }
    77. bool f=false;
    78. for(int i=0;i<=1000;i++)//枚举s24可能的情况
    79. if(spfa(i))
    80. {
    81. cout<
    82. f=true;
    83. break;
    84. }
    85. if(!f) puts("No Solution");
    86. }
    87. return 0;
    88. }

  • 相关阅读:
    【PostgreSQL】主键添加自增
    【Kubernetes | Pod 系列】Pod 的基本管理(3)——对 Pod 的删除与修改
    【Linux】Linux常用操作命令
    django 开启CSRFtoken校验,以及postman实现问题
    数据结构 | (三) Stack
    AI办公自动化:批量根据Excel表格内容制作Word文档
    HCIP之BGP的路由聚合
    PPT素材、PPT模板免费下载
    08_一句话让你人间清醒
    Java版本spring cloud + spring boot企业电子招投标系统源代码
  • 原文地址:https://blog.csdn.net/m0_63729880/article/details/126268525