现在有三个工作站,有三种工作,每种工作需要完成前置任务才能进行当前工作,三个工作站之间转换需要花费时间,问将所有任务都完成需要花费的最少时间。一开始可以在任意一个工作站开始工作。
思路:
仔细观察三个工作站之间转换需要花费的时间不难发现,我们从1如果想要去3的话,不妨先到2一次,再到3,距离都是2.
同理,如果想从2到1的话,不妨先到3一次,再到1,距离也是2.
那么其实我们就可以枚举一个起点,然后每一次将当前站(now)能够做的工作全部做完,然后转到下一个工作站继续工作(now+1)去进行能够进行的工作即可。
那么整个工作的过程就是不断的1->2->3->1->2->3去循环往复的做就行了。直到所有任务都完成。
做任务的过程暴力拓扑一下就行。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
vector<int>mp[15000];
int d[5][5];
int a[2500];
int degree[2500];
int n;
int Slove(int ss)
{
queue<int>s;
int ans=n;
int cont=0;
int now=ss;
while(1)
{
while(1)
{
int flag=0;
for(int i=1;i<=n;i++)
{
if(degree[i]==0&&a[i]==now)
{
flag=1;
degree[i]=-1;
cont++;
for(int j=0;j<mp[i].size();j++)
{
int v=mp[i][j];
degree[v]--;
}
}
}
if(flag==0)break;
}
if(cont==n)break;
now++;
ans++;
if(now==4)now=1;
}
return ans;
}
int temp[15000];
int main()
{
d[1][1]=0;d[1][2]=1;d[1][3]=2;
d[2][1]=2;d[2][2]=1;d[2][3]=1;
d[3][1]=1;d[3][2]=1;d[3][3]=0;
while(~scanf("%d",&n))
{
memset(degree,0,sizeof(degree));
for(int i=1;i<=n;i++)mp[i].clear();
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
int ki;scanf("%d",&ki);
for(int j=1;j<=ki;j++)
{
int x;scanf("%d",&x);
mp[x].push_back(i);
degree[i]++;
}
}
for(int i=1;i<=n;i++)temp[i]=degree[i];
int ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)degree[i]=temp[i];
ans=min(ans,Slove(1));
for(int i=1;i<=n;i++)degree[i]=temp[i];
ans=min(ans,Slove(2));
for(int i=1;i<=n;i++)degree[i]=temp[i];
ans=min(ans,Slove(3));
printf("%d\n",ans);
}
}