• 图论


    POJ 2449 Remmarguts' Date

    K短路。

    A*+迪杰斯特拉,虽然像是spfa 但是用的迪杰斯特拉的思想,每次找到最小,然后更新。

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF 0x3ffffff
    struct node
    {
        int u,v,w,next;
    }edge[100001];
    int qu[100001],qv[100001],qw[100001];
    struct fnode
    {
        int g,h,u;
        bool operator < (fnode a)const
        {
            return a.g + a.h < h + g;
        }
    };
    int first[1001];
    int dis[1001];
    int cnt[1001];
    int in[1001];
    int t,str,end,n,k;
    /*
    f[n] = h[n] + g[n];
    h代表n到end的最短距离
    g是在状态空间中从初始节点到n节点的实际代价
    */
    void CL()
    {
        t = 1;
        memset(first,-1,sizeof(first));
    }
    void add(int u,int v,int w)
    {
        edge[t].u = t;
        edge[t].v = v;
        edge[t].w = w;
        edge[t].next = first[u];
        first[u] = t ++;
    }
    void spfa()
    {
        int u,v,i;
        for(i = 1;i <= n;i ++)
        {
            dis[i] = INF;
            in[i] = 0;
        }
        queue<int>que;
        dis[str] = 0;
        in[str] = 1;
        que.push(str);
        while(!que.empty())
        {
            u = que.front();
            in[u] = 0;
            que.pop();
            for(i = first[u];i != -1;i = edge[i].next)
            {
                v = edge[i].v;
                if(dis[v] > dis[u] + edge[i].w)
                {
                    dis[v] = dis[u] + edge[i].w;
                    if(!in[v])
                    {
                        in[v] = 1;
                        que.push(v);
                    }
                }
            }
        }
    }
    int Astar()
    {
        fnode cur,nxt;
        int i;
        memset(cnt,0,sizeof(cnt));
        priority_queue <fnode> que;
        cur.u = str;
        cur.g = 0;
        cur.h = dis[cur.u];
        que.push(cur);
        while(!que.empty())
        {
            cur = que.top();
            que.pop();
            cnt[cur.u] ++;
            if(cnt[cur.u] > k) continue;
            if(cnt[end] == k)
            {
                return cur.g;
            }
            for(i = first[cur.u];i != -1;i = edge[i].next)
            {
                nxt.u = edge[i].v;
                nxt.g = cur.g + edge[i].w;
                nxt.h = dis[edge[i].v];
                que.push(nxt);
            }
        }
        return -1;
    }
    int main()
    {
        int i,m,S,T;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            CL();
            for(i = 0;i < m;i ++)
            {
                scanf("%d%d%d",&qu[i],&qv[i],&qw[i]);
                add(qv[i],qu[i],qw[i]);
            }
            scanf("%d%d%d",&S,&T,&k);
            if(S == T)k ++;//
            str = T;
            end = S;
            spfa();
            CL();
            for(i = 0;i < m;i ++)
            {
                add(qu[i],qv[i],qw[i]);
            }
            str = S;
            end = T;
            printf("%d
    ",Astar());
        }
        return 0;
    }
    View Code

    POJ 3013 Big Christmas Tree

    有意思的一题,把求和式子转换一下,就是最短路了。

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF 20000000000LL
    #define LL long long
    struct node
    {
        int u,v,w,next;
    }edge[210000];
    int first[50100];
    LL dis[50100];
    int in[50100];
    int wgt[50100];
    int t,n;
    void CL()
    {
        t = 1;
        memset(first,-1,sizeof(first));
    }
    void add(int u,int v,int w)
    {
        edge[t].u = u;
        edge[t].v = v;
        edge[t].w = w;
        edge[t].next = first[u];
        first[u] = t ++;
    }
    LL spfa()
    {
        int i,u,v;
        for(i = 1;i <= n;i ++)
        {
            dis[i] = INF;
            in[i] = 0;
        }
        queue<int> que;
        in[1] = 1;
        dis[1] = 0;
        que.push(1);
        while(!que.empty())
        {
            u = que.front();
            in[u] = 0;
            que.pop();
            for(i = first[u];i != -1;i = edge[i].next)
            {
                v = edge[i].v;
                if(dis[v] > dis[u] + edge[i].w)
                {
                    dis[v] = dis[u] + edge[i].w;
                    if(!in[v])
                    {
                        in[v] = 1;
                        que.push(v);
                    }
                }
            }
        }
        LL ans = 0;
        for(i = 1;i <= n;i ++)
        {
            if(dis[i] == INF)
            return -1;
            ans += dis[i]*wgt[i];
        }
        return ans;
    }
    int main()
    {
        int cas,i,m;
        scanf("%d",&cas);
        while(cas--)
        {
            CL();
            scanf("%d%d",&n,&m);
            for(i = 1;i <= n;i ++)
            scanf("%d",&wgt[i]);
            for(i = 0;i < m;i ++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);
                add(v,u,w);
            }
            LL ans = spfa();
            if(ans == -1)
            printf("No Answer
    ");
            else
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    POJ 3463 Sightseeing

    最短路条数+次短路条数,spfa形式的迪杰斯特拉,不是很懂此题的思路。

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF 0x3ffffff
    struct node
    {
        int u,v,w,next;
    }edge[100000];
    int first[10000];
    int dis[10000][2];
    int cnt[10000][2];
    int in[10000][2];
    int n,t,S,T;
    struct fnode
    {
        int u,w,k;
        bool operator < (fnode a)const
        {
            return a.w < w;
        }
    };
    void CL()
    {
        t = 1;
        memset(first,-1,sizeof(first));
    }
    void add(int u,int v,int w)
    {
        edge[t].u = u;
        edge[t].v = v;
        edge[t].w = w;
        edge[t].next = first[u];
        first[u] = t ++;
    }
    int spfa()
    {
       int i,j,u,v;
       fnode cur,nxt;
       for(i = 1;i <= n;i ++)
       {
           for(j = 0;j < 2;j ++)
           {
               dis[i][j] = INF;
               cnt[i][j] = 0;
               in[i][j] = 0;
           }
       }
       dis[S][0] = 0;
       cnt[S][0] = 1;
       cnt[S][1] = 1;
       priority_queue<fnode>que;
       cur.u = S;
       cur.w = 0;
       cur.k = 0;
       que.push(cur);
       while(!que.empty())
       {
           cur = que.top();
           que.pop();
           u = cur.u;
           if(in[u][cur.k])
           continue;
           in[u][cur.k] = 1;
           for(i = first[u];i != -1;i = edge[i].next)
           {
               v = edge[i].v;
               if(dis[v][0] > cur.w + edge[i].w)
               {
                   dis[v][1] = dis[v][0];
                   cnt[v][1] = cnt[v][0];
                   dis[v][0] = cur.w + edge[i].w;
                   cnt[v][0] = cnt[u][cur.k];
                   nxt.u = v;
                   nxt.w = dis[v][0];
                   nxt.k = 0;
                   que.push(nxt);
                   nxt.u = v;
                   nxt.w = dis[v][1];
                   nxt.k = 1;
                   que.push(nxt);
               }
               else if(dis[v][0] == cur.w + edge[i].w)
               {
                   cnt[v][0] += cnt[u][cur.k];
               }
               else if(dis[v][1] > cur.w + edge[i].w)
               {
                   dis[v][1] = cur.w + edge[i].w;
                   cnt[v][1] = cnt[u][cur.k];
                   nxt.u = v;
                   nxt.w = dis[v][1];
                   nxt.k = 1;
                   que.push(nxt);
               }
               else if(dis[v][1] == cur.w + edge[i].w)
               {
                   cnt[v][1] += cnt[u][cur.k];
               }
           }
       }
       if(dis[T][0] == dis[T][1]-1)
       return cnt[T][0] + cnt[T][1];
       else
       return cnt[T][0];
    }
    int main()
    {
        int cas,m,i,u,v,w;
        scanf("%d",&cas);
        while(cas--)
        {
            CL();
            scanf("%d%d",&n,&m);
            for(i = 0;i < m;i ++)
            {
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);
            }
            scanf("%d%d",&S,&T);
            printf("%d
    ",spfa());
        }
        return 0;
    }
    View Code

     POJ 3613 Cow Relays

    s 到 e的经过了n条边的最短路。

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF 1000000000
    int p[301][301];
    int ans[301][301];
    int dis[301][301];
    int tmp[301][301];
    int qu[501];
    int qv[501];
    int qw[501];
    int que[501];
    int flag[1001];
    int num,s,e;
    #define MAXN 301
    void floyd(int c[][MAXN], int a[][MAXN], int b[][MAXN])
    {
        for(int k = 1; k < num; k++)
            for(int i = 1; i < num; i++)
                for(int j = 1; j < num; j++)
                    if(c[i][j] > a[i][k] + b[k][j])
                        c[i][j] = a[i][k] + b[k][j];
    }
    void copy(int a[][MAXN], int b[][MAXN])
    {
        for(int i = 1; i < num; i++)
            for(int j = 1; j < num; j++)
            {
                a[i][j] = b[i][j];
                b[i][j] = INF;
            }
    }
    int qmod(int k)
    {
        while(k)
        {
            if(k & 1)
            {
                floyd(dis, ans, p);
                copy(ans, dis);
            }
            floyd(tmp, p, p);
            copy(p, tmp);
            k >>= 1;
        }
        return ans[flag[s]][flag[e]];
    }
    int main()
    {
        int i,j,n,m,u,v,w;
        scanf("%d%d%d%d",&n,&m,&s,&e);
        for(i = 1; i <= 300; i ++)
        {
            for(j = 1; j <= 300; j ++)
            {
                p[i][j] = INF;
                ans[i][j] = INF;
                dis[i][j] = INF;
                tmp[i][j] = INF;
            }
            ans[i][i] = 0;//注意这里
        }
        num = 1;
        for(i = 0; i < m; i ++)
        {
            scanf("%d%d%d",&qw[i],&qu[i],&qv[i]);
            if(flag[qu[i]] == 0)
                flag[qu[i]] = num++;
            if(flag[qv[i]] == 0)
                flag[qv[i]] = num++;
            u = flag[qu[i]];
            v = flag[qv[i]];
            w = qw[i];
            p[u][v] = min(p[u][v],w);
            p[v][u] = min(p[v][u],w);
        }
        printf("%d
    ",qmod(n));
    }
    View Code

     POJ 3621 Sightseeing Cows

    最优比率生成环

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define eps 1e-3
    struct node
    {
        int u,v,next;
        double w;
    }edge[10000];
    int p[1001];
    int first[1001];
    double dis[1001];
    int in[1001];
    int num[1001];
    int t,n;
    void CL()
    {
        t = 1;
        memset(first,-1,sizeof(first));
    }
    void add(int u,int v,int w)
    {
        edge[t].u = u;
        edge[t].v = v;
        edge[t].w = w;
        edge[t].next = first[u];
        first[u] = t ++;
    }
    int spfa(double r)
    {
        int i,u,v;
        double w;
        for(i = 1;i <= n;i ++)
        {
            dis[i] = INF;
            num[i] = 0;
            in[i] = 0;
        }
        dis[1] = 0;
        in[1] = 1;
        queue<int>que;
        que.push(1);
        while(!que.empty())
        {
            u = que.front();
            que.pop();
            in[u] = 0;
            for(i = first[u];i != -1;i = edge[i].next)
            {
                v = edge[i].v;
                w = -p[v] + r*edge[i].w;
                if(dis[v] > dis[u] + w)
                {
                    dis[v] = dis[u] + w;
                    if(!in[v])
                    {
                        in[v] = 1;
                        num[v] ++;
                        if(num[v] > n)
                        return 1;
                        que.push(v);
                    }
                }
            }
        }
        return 0;
    }
    int main()
    {
        int m,i,u,v;
        double w;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            CL();
            for(i = 1;i <= n;i ++)
            scanf("%d",&p[i]);
            for(i = 1;i <= m;i ++)
            {
                scanf("%d%d%lf",&u,&v,&w);
                add(u,v,w);
            }
            double str,end,mid;
            str = 0;
            end = 10000000;
            while(str+eps < end)
            {
                mid = (str + end)/2;
                if(spfa(mid))
                str = mid;
                else
                end = mid;
            }
            printf("%.2lf
    ",str);
        }
    
        return 0;
    }
    View Code

     POJ 3635 Full Tank?

    二维的spfa,这题主要是会超时,首先转移有两种,加1单位的油或者 走向下个城市,这样会spfa的比较快,然后写成spfa形式的迪杰斯特拉,就可AC。

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define eps 1e-3
    struct node
    {
        int u,v,w,next;
    } edge[30000];
    struct city
    {
        int u,c,w;
        bool operator < (city a)const
        {
            return a.w < w;
        }
    };
    int t,n;
    int first[1001];
    int p[1001];
    int dis[1001][101];
    int in[1001][101];
    int s,e,c;
    void CL()
    {
        t = 1;
        memset(first,-1,sizeof(first));
    }
    void add(int u,int v,int w)
    {
        edge[t].u = u;
        edge[t].v = v;
        edge[t].w = w;
        edge[t].next = first[u];
        first[u] = t ++;
    }
    int spfa()
    {
        int i,j,u,v,tc;
        city cur,nxt;
        for(i = 0; i < n; i ++)
        {
            for(j = 0; j <= c; j ++)
            {
                dis[i][j] = INF;
                in[i][j] = 0;
            }
        }
        priority_queue<city>que;
        cur.u = s;
        cur.c = 0;
        cur.w = 0;
        dis[cur.u][cur.c] = 0;
        in[s][0] = 1;
        que.push(cur);
        while(!que.empty())
        {
            cur = que.top();
            u = cur.u;
            tc = cur.c;
            que.pop();
            if(u == e)
            return cur.w;
            in[u][tc] = 0;
            if(tc + 1 <= c)//加油
            {
                if(dis[u][tc+1] > dis[u][tc] + p[u])
                {
                    dis[u][tc+1] = dis[u][tc] + p[u];
                    v = u;
                    j = tc+1;
                    nxt.u = v;
                    nxt.c = j;
                    nxt.w = dis[v][j];
                    que.push(nxt);
                }
            }
            for(i = first[u]; i != -1; i = edge[i].next)
            {
                v = edge[i].v;
                if(tc >= edge[i].w)//走点
                {
                    j = tc-edge[i].w;
                    if(dis[v][j] > dis[u][tc])
                    {
                        dis[v][j] = dis[u][tc];
                        nxt.u = v;
                        nxt.c = j;
                        nxt.w = dis[v][j];
                        que.push(nxt);
                    }
                }
            }
        }
        return -1;
    }
    int main()
    {
        int m,i,q;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            CL();
            for(i = 0; i < n; i ++)
                scanf("%d",&p[i]);
            for(i = 0; i < m; i ++)
            {
                int u,v,w;
                scanf("%d%d%d",&u,&v,&w);
                add(u,v,w);
                add(v,u,w);
            }
            scanf("%d",&q);
            while(q--)
            {
                scanf("%d%d%d",&c,&s,&e);
                int temp = spfa();
                if(temp == -1)
                    printf("impossible
    ");
                else
                    printf("%d
    ",temp);
            }
        }
        return 0;
    }
    View Code

     POJ 2728 Desert King

    最优比率生成树

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <string>
    #include <set>
    #include <map>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF 100000000
    #define eps 1e-4
    struct node
    {
        double x,y,z;
        double w;
    }p[1001];
    double low[1001];
    int o[1001],n;
    double fun(int u,int v,double mid)
    {
        double l,c;
        l = sqrt((p[u].x-p[v].x)*(p[u].x-p[v].x) + (p[u].y-p[v].y)*(p[u].y-p[v].y));
        c = fabs(p[u].z-p[v].z);
        return c-mid*l;
    }
    double judge(double mid)
    {
        int i,j,k;
        double ans = 0,minz;
        for(i = 1;i <= n;i ++)
        {
            low[i] = INF;
            o[i] = 0;
        }
        low[1] = 0;
        for(i = 1;i <= n;i ++)
        {
            minz = INF;
            for(j = 1;j <= n;j ++)
            {
                if(!o[j]&&minz > low[j])
                {
                    minz = low[j];
                    k = j;
                }
            }
            o[k] = 1;
            ans += minz;
            for(j = 1;j <= n;j ++)
            {
                double temp = fun(k,j,mid);
                if(!o[j]&&low[j] > temp)
                {
                    low[j] = temp;
                }
            }
        }
        return ans;
    }
    int main()
    {
        int i;
        double str,end,mid;
        while(scanf("%d",&n)!=EOF)
        {
            if(n == 0) break;
            for(i = 1;i <= n;i ++)
            {
                scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);
            }
            str = 0;
            end = 100000;
            while(str + eps < end)
            {
                mid = (str + end)/2;
                if(judge(mid) <= 0)
                end = mid;
                else
                str = mid;
            }
            printf("%.3lf
    ",str);
        }
        return 0;
    }
    View Code

    POJ 3164 Command Network

    最小树形图,抄的模板,把序号 改成从1开始不知道为什么过不了。

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <string>
    #include <set>
    #include <map>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF ~0u>>1
    #define N 1001
    #define eps 1e-8
    int t;
    struct node
    {
        int u,v;
        double w;
    } edge[100000];
    struct point
    {
        double x,y;
    } p[N];
    double in[N];
    int pre[N];
    int vis[N];
    int id[N];
    int n,m;
    
    double dis(point a,point b)
    {
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    double Directed_MST(int root)
    {
        double ret = 0;
        int i, u, v;
        while(true)
        {
            for(i = 0; i < n; i ++)
            in[i] = INF;
            for(i = 1;i <= m;i ++)
            {
                u = edge[i].u;
                v = edge[i].v;
                if(edge[i].w < in[v] && u != v)
                {
                    in[v] = edge[i].w;
                    pre[v] = u;
                }
            }
            for(i = 0;i < n;i ++)     //如果存在除root以外的孤立点,则不存在最小树形图
            {
                if(i == root)   continue;
                if(in[i] == INF)    return -1;
            }
            int cnt = 0;
            memset(id,-1,sizeof(id));
            memset(vis,-1,sizeof(vis));
            in[root] = 0;
            for(i = 0;i < n;i ++)    //找环
            {
                ret += in[i];
                int v = i;
                while(vis[v] != i && id[v] == -1 && v != root)
                {
                    vis[v] = i;
                    v = pre[v];
                }
                if(v != root && id[v] == -1)    //重新标号
                {
                    for(u = pre[v]; u != v; u = pre[u])
                    {
                        id[u] = cnt;
                    }
                    id[v] = cnt++;
                }
            }
            if(cnt == 0)    break;
            for(i = 0;i < n;i ++)
            {
                if(id[i] == -1) id[i] = cnt++;    //重新标号
            }
            for(i = 1;i <= m;i ++)     //更新其他点到环的距离
            {
                v = edge[i].v;
                edge[i].u = id[edge[i].u];
                edge[i].v = id[edge[i].v];
                if(edge[i].u != edge[i].v)
                {
                    edge[i].w -= in[v];
                }
            }
            n = cnt;
            root = id[root];
        }
        return ret;
    }
    int main()
    {
        int i,u,v;
        double ans;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(i = 0; i < n; i ++)
            {
                scanf("%lf%lf",&p[i].x,&p[i].y);
            }
            for(i = 1; i <= m; i ++)
            {
                scanf("%d%d",&u,&v);
                u --;
                v --;
                edge[i].u = u;
                edge[i].v = v;
                edge[i].w = dis(p[u],p[v]);
            }
            ans = Directed_MST(0);
            if(ans == -1)
                printf("poor snoopy
    ");
            else
                printf("%.2f
    ",ans);
        }
        return 0;
    }
    View Code

    POJ 3522 Slim Span

    暴力...

    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <algorithm>
    #include <stdlib.h>
    #include <vector>
    #include <cmath>
    #include <queue>
    #include <string>
    #include <set>
    #include <map>
    #include <stack>
    #include <queue>
    #include <cstring>
    using namespace std;
    #define INF 0x7ffffff
    struct node
    {
        int u,v,w;
    }edge[10001];
    int o[101];
    int num;
    bool cmp(node a,node b)
    {
        return a.w < b.w;
    }
    int find(int x)
    {
        while(x != o[x])
        x = o[x];
        return x;
    }
    
    void merge(int x,int y)
    {
        x = find(x);
        y = find(y);
        if(o[x] != y)
        {
            num ++;
            o[x] = y;
        }
    }
    
    int main()
    {
        int u,v,i,j,w,ans,n,m;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            if(n == 0&&m == 0) break;
            for(i = 0;i < m;i ++)
            scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
            sort(edge,edge+m,cmp);
            ans = INF;
            for(i = 0;i < m;i ++)
            {
                for(j = 1;j <= n;j ++)
                o[j] = j;
                num = 0;
                for(j = i;j < m;j ++)
                {
                    u = edge[j].u;
                    v = edge[j].v;
                    w = edge[j].w;
                    if(w - edge[i].w > ans)
                    break;
                    merge(u,v);
                    if(num == n-1)
                    {
                        ans = min(ans,w-edge[i].w);
                        break;
                    }
                }
            }
            if(ans == INF)
            printf("-1
    ");
            else
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    python动态规划解决矩阵连乘
    ISCC2019-digdigdig
    MultiSelectComboBox(一)
    中国地图 xaml Canvas
    NotificationObject.cs
    DelegateCommand.cs
    SQL-PIVOT 数据透视 行列转换
    中国行政区域(省,市,县)SQL
    WCF自定义地址路由映射(不用svc文件)
    java下载安装,环境变量,hello world
  • 原文地址:https://www.cnblogs.com/naix-x/p/3878550.html
Copyright © 2020-2023  润新知