• Bzoj4773 负环


    Time Limit: 100 Sec  Memory Limit: 256 MB
    Submit: 194  Solved: 97

    Description

    在忘记考虑负环之后,黎瑟的算法又出错了。对于边带权的有向图 G = (V, E),请找出一个点数最小的环,使得
    环上的边权和为负数。保证图中不包含重边和自环。
     
     

    Input

    第1两个整数n, m,表示图的点数和边数。
    接下来的m行,每<=三个整数ui, vi, wi,表<=有一条从ui到vi,权值为wi的有向边。
    2 <= n <= 300
    0 <= m <= n(n <= 1)
    1 <= ui, vi <= n
    |wi| <= 10^4
     

    Output

    仅一行一个整数,表示点数最小的环上的点数,若图中不存在负环输出0。
     

    Sample Input

    3 6
    1 2 -2
    2 1 1
    2 3 -10
    3 2 10
    3 1 -10
    1 3 10

    Sample Output

    2

    HINT

     

    Source

    二分答案判负环

    用倍增什么的搞一搞就好了。

    然而试图用SPFA水过去的时候发现我可能连SPFA都不会写了

     1 /*by SilverN*/
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 const int mxn=100010;
    10 int read(){
    11     int x=0,f=1;char ch=getchar();
    12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    14     return x*f;
    15 }
    16 struct edge{
    17     int v,nxt,w;
    18 }e[mxn<<1];
    19 int hd[mxn],mct=0;
    20 void add_edge(int u,int v,int w){
    21     e[++mct].v=v;e[mct].nxt=hd[u];e[mct].w=w;hd[u]=mct;return;
    22 }
    23 int lim;
    24 int inq[mxn],dis[mxn];
    25 bool SPFA(int u,int time){
    26     if(inq[u])return 1;
    27     if(time>lim)return 0;
    28     inq[u]=1;
    29     for(int i=hd[u];i;i=e[i].nxt){
    30         int v=e[i].v;
    31         if(dis[v]>=dis[u]+e[i].w){
    32             dis[v]=dis[u]+e[i].w;
    33             if(SPFA(v,time+1))return 1;
    34         }
    35     }
    36     inq[u]=0;
    37     return 0;
    38 }
    39 int n,m;
    40 bool chk(){
    41     for(int i=1;i<=n;i++){
    42         memset(dis,0x3f,sizeof dis);
    43         memset(inq,0,sizeof inq);
    44         if(SPFA(i,1))return 1;
    45     }
    46     return 0;
    47 }
    48 void solve(){
    49     int l=1,r=n;
    50     int res=0;
    51     while(l<=r){
    52         int mid=(l+r)>>1;
    53         lim=mid;
    54         memset(inq,0,sizeof inq);
    55         if(chk()){
    56             res=mid;
    57             r=mid-1;
    58         }
    59         else l=mid+1;
    60     }
    61     printf("%d
    ",res);
    62     return;
    63 }
    64 int main(){
    65     int i,j,u,v,w;
    66     n=read();m=read();
    67     for(i=1;i<=m;i++){
    68         u=read();v=read();w=read();
    69         add_edge(u,v,w);
    70     }
    71     solve();
    72     return 0;
    73 }
    WA

    为啥会错啊……

    非要把inq放在循环里面才能过……

    ——————updated

    仔细想想好像确实是这样,起初的u并没有被更新过就直接入队,会导致不必要的错误。

    但是循环枚举起点的时候把dis[i]设成0,也过不了,无限TLE。

    大概理解还是不透彻

    ——————

     1 /*by SilverN*/
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #include<cstdio>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 const int mxn=310;
    10 int read(){
    11     int x=0,f=1;char ch=getchar();
    12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
    14     return x*f;
    15 }
    16 struct edge{
    17     int v,nxt,w;
    18 }e[mxn*mxn];
    19 int hd[mxn],mct=0;
    20 void add_edge(int u,int v,int w){
    21     e[++mct].v=v;e[mct].nxt=hd[u];e[mct].w=w;hd[u]=mct;return;
    22 }
    23 int lim;
    24 int inq[mxn],dis[mxn];
    25 bool SPFA(int u,int time){
    26     for(int i=hd[u];i;i=e[i].nxt){
    27         int v=e[i].v;
    28         if(dis[v]>=dis[u]+e[i].w){
    29             if(inq[v])return 1;
    30             if(time==lim)return 0;
    31             dis[v]=dis[u]+e[i].w;
    32             inq[v]=1;
    33             if(SPFA(v,time+1))return 1;
    34             inq[v]=0;
    35         }
    36     }
    37     return 0;
    38 }
    39 int n,m;
    40 bool chk(){
    41     for(int i=1;i<=n;i++){
    42         memset(dis,0,sizeof dis);
    43         memset(inq,0,sizeof inq);
    44         dis[i]=0;inq[i]=1;
    45         if(SPFA(i,1))return 1;
    46     }
    47     return 0;
    48 }
    49 void solve(){
    50     int l=1,r=n;
    51     int res=0;
    52     while(l<=r){
    53         int mid=(l+r)>>1;
    54         lim=mid;
    55         memset(inq,0,sizeof inq);
    56         if(chk()){
    57             res=mid;
    58             r=mid-1;
    59         }
    60         else l=mid+1;
    61     }
    62     printf("%d
    ",res);
    63     return;
    64 }
    65 int main(){
    66     int i,j,u,v,w;
    67     n=read();m=read();
    68     for(i=1;i<=m;i++){
    69         u=read();v=read();w=read();
    70         add_edge(u,v,w);
    71     }
    72     solve();
    73     return 0;
    74 }
    AC
  • 相关阅读:
    struts开发步骤
    线程同步及同步变量
    pthread_detach pthread_join pthread_create
    NSThread
    Java线程中run和start方法的区别
    java的守护线程与非守护线程
    多线程的多重属性
    Java Observer 观察者
    Java_观察者模式(Observable和Observer)
    任务、进程和线程
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6636177.html
Copyright © 2020-2023  润新知